Git Product home page Git Product logo

spring-projects / spring-data-r2dbc Goto Github PK

View Code? Open in Web Editor NEW
704.0 45.0 129.0 3.51 MB

Provide support to increase developer productivity in Java when using Reactive Relational Database Connectivity. Uses familiar Spring concepts such as a DatabaseClient for core API usage and lightweight repository style data access.

License: Apache License 2.0

reactive relational spring framework spring-data ddd r2dbc

spring-data-r2dbc's Introduction

spring-data-r2dbc's People

Contributors

ada-waffles avatar berry120 avatar christophstrobl avatar dependabot[bot] avatar digimon1740 avatar gregturn avatar gzsombor avatar hirakida avatar joselion avatar kamalhm avatar lifenjoy51 avatar ljrmorgan avatar m1ngyuan avatar making avatar manousos avatar michael-simons avatar mirromutth avatar mp911de avatar n0mer avatar odrotbohm avatar okue avatar orange-buffalo avatar oshai avatar pull-vert avatar rchigvintsev avatar rdegnan avatar schauder avatar sdeleuze avatar spring-operator avatar yangyuanqiang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-data-r2dbc's Issues

Flawed naming convention

Take a look at this

databaseClient.execute()
  .sql("INSERT INTO legoset (id, name, manual) VALUES($1, $2, $3)")
  .bind("$1", 42055)
  .bind("$2", "Description")
  .bindNull("$3", Integer.class)
  .fetch()

The method name execute() sounds & feels like we are executing something, not building a query for execution. For comparison, just try to understand what is fetch & what is execute in general. Both are ACTIONs, but the API expects us to treat them differently for no good reason. For a user who knows nothing about Spring Data R2DBC, execute API is not at all intuitive

I saw the same flawed naming convention being followed in WebClient api of webflux when it comes to building http requests, i.e inorder to build a GET request, they expect us to write webClient.get(), but this sounds & feels like we are making GET call when we are writing it (as per intuition), but we with WebFlux api we are not making the call with get, rather we are informing the API to return a *Builder/*Spec that will eventually make a GET request. Its a flawed API design as it breaks intuition

I have couple of suggestions about it

Either name methods that build something with op<Builder>() (or) for<Op>, i.e for building execute statements use databaseClient.executeBuilder() (or) databaseClient.forExecute()

The first one is more direct & does not leave any space for any confusion

Use TestContainers for integration tests

Right now, we require locally running databases to run our tests. We should allow for using TestContainers to reduce build requirements (Docker instead of multiple databases).

Add support for parameter bind markers

R2DBC uses native parameter bind markers ($1, $2 for Postgres, @foo, @bar for Microsoft SQL Server). Native bind markers require a specific adaption within queries to use the appropriate bind marker and to properly bind parameters.

We should introduce a component to create bind markers (for dynamic SQL generation) and to bind parameters that both honor the native specifics.

Parameter binding is a pre-requisite to creating a translation layer which accepts standardized parameter declaration (e.g. named parameters such as in NamedParameterJdbcTemplate)

Add support of DataSource configuration

Currently Spring data Jdbc/JPA can recognize spring.datasource and build a DataSource bean, if possible create a ConnectionFactory bean from spring.datasource automatically if it is configured in Spring Boot applications?

Entity with assigned Id is not inserted

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
  @Id private String id;
  private String name;
}


import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface PeopleRepository extends ReactiveCrudRepository<People, String> {
}


@Autowired private PeopleRepository repository;
@Test
void test() {
  // save it
  People po = new People();
  po.setId(UUID.randomUUID().toString());
  po.setName("simter");
  StepVerifier.create(repository.save(po))
    .expectNext(po)
    .verifyComplete();

  // verify saved
  StepVerifier.create(repository.findById(po.getId()))
    .expectNext(po)
    .verifyComplete();
}

I log out io.r2dbc.h2.client.SessionClient as debug, request a update sql not insert into sql. Entity not saved and repository.findById found nothing.

···
2019-01-11 11:37:00.404 DEBUG io.r2dbc.h2.client.SessionClient : Request: UPDATE people SET name = $2 WHERE id = $1 {1: '1d7d50d3-b1a3-4c27-8552-00d2bf9c5b08', 2: 'simter'}
···

Add support for simple type projections

I'm using spring-data-r2dbc-1.0.0.M1 with r2dbc-postgresql-1.0.0.M6. See below code, failed to select single field value.

Code :

public class Dream {
  @Id private Integer id;
  private String name;
  ...
}
public interface DreamRepository extends ReactiveCrudRepository<Dream, Integer> {
  @Query("select name from dream")
  Flux<String> findAllName();
}

Error message :

org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class java.lang.String!

  at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:79)
  at org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy.getRequiredPersistentEntity(DefaultReactiveDataAccessStrategy.java:242)
  at org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy.getRowMapper(DefaultReactiveDataAccessStrategy.java:228)
  at org.springframework.data.r2dbc.function.DefaultDatabaseClient$DefaultTypedExecuteSpec.<init>(DefaultDatabaseClient.java:476)
  at org.springframework.data.r2dbc.function.DefaultDatabaseClient.createTypedExecuteSpec(DefaultDatabaseClient.java:223)
  at org.springframework.data.r2dbc.function.DefaultDatabaseClient$DefaultGenericExecuteSpec.as(DefaultDatabaseClient.java:408)
  at org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery.execute(AbstractR2dbcQuery.java:106)
  at org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery.execute(AbstractR2dbcQuery.java:84)
  at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
  ...
  at com.sun.proxy.$Proxy38.findAllName(Unknown Source)
  at tech.simter.start.r2dbc.spring.dao.FindAllNameMethodImplTest.test(FindAllNameMethodImplTest.java:40)
  ...

My unit test code is FindAllNameMethodImplTest.java

RETURNING * does not work on H2

#10 gives me a regression on h2:

Syntax error in SQL statement "INSERT INTO NEWS_USER (FIRSTNAME,LASTNAME,USERNAME,PASSWORD) VALUES($1,$2,$3,$4) RETURNING[*] * "

I guess H2 does support only returning id.

Add R2DBC-specific exception translation

Right now, we're using Spring Framework's JDBC module to apply exception translation. Spring JDBC is heavily based on JDBC API and it makes little sense to pull JDBC API into R2DBC, especially when running in modularized Java 9+ environments.

We should provide our own exception translation mechanism that is built along the lines of Spring JDBC's SQLErrorCodes without using JDBC API.

Don't depend on MSSQL JDBC driver

Currently, when I add this library as a dependency, it automatically pulls mssql-jdbc driver. I am not sure if this intentional. Can someone please check if this is indeed intentional?

Ref:

spring-data-r2dbc/pom.xml

Lines 241 to 245 in 3d1041c

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${mssql-jdbc.version}</version>
</dependency>

Add support for MariaDB

No spring r2dbc for mariadb exists as of today. As said in https://r2dbc.io/ videos there is a support mentioned 2 months back in works. So please do help in providing initial repository (mariadb r2dbc) for community to test and give feedback.

Add abstract configuration class for R2DBC

We should provide an abstract R2dbcConfiguration class that configures components which are required to spin up repositories. These are a ConnectionFactory and DatabaseClient

IllegalStateException during inTransaction(…) with inner Mono.error(…)

The following code causes an IllegalStateException:

client
    .inTransaction(
        dc ->
            passwordHistoryRepository
                .save(new PasswordHistory(1))
                .then(Mono.error(new RuntimeException("6")))
                .then(passwordHistoryRepository.save(new PasswordHistory(2))
    )

Trace:

RuntimeException, trace=java.lang.RuntimeException: Async resource cleanup failed after onComplete
	at reactor.core.publisher.FluxUsingWhen$CommitInner.onError(FluxUsingWhen.java:519)
...
Caused by: java.lang.IllegalStateException: Connection is closed!
	at org.springframework.data.r2dbc.function.connectionfactory.SingletonConnectionFactory.create(SingletonConnectionFactory.java:54)
	at org.springframework.data.r2dbc.function.DefaultTransactionalDatabaseClient.lambda$cleanup$7(DefaultTransactionalDatabaseClient.java:142)

Related ticket: #44.

Add support for Custom Conversions for array-types

We should add R2dbcCustomConversions to distinguish between entity types and non-entity types.
Right now, String[] is considered an entity as well as List and Collection. For Postgres, we would like to read and write array types.

Add Query-Pre-Processor

We should consider adding a Query Pre-Processor API that allows generic pre-processing of queries. The first use-case of query-pre-processing is named parameter expansion (see #23). Another case can be generic query augmentation to add or remove parts of a query and to mutate bound parameters. Query pre-processors can be modeled as a filter function to compose a chain of functions.

Consider custom conversion in EntityRowMapper and MappingR2dbcConverter

Reading of Map entity property is intentionally blocked by above line.

How about allowing it and then delegate to the client's custom DBStoredValue-To-Map converter. Similar to:

    static class Config extends AbstractR2dbcConfiguration {

        @Override @Bean public R2dbcCustomConversions r2dbcCustomConversions() {
            ...
            return new R2dbcCustomConversions(
                    storeConversions,
                    Arrays.asList(new JsonStringToMapConverter()));
        }

        class JsonStringToMapConverter implements Converter<String, Map<String, Object>> {
             ...
        }

H2Statement does not define or inherit an implementation of bind(Ljava/lang/Integer;Ljava/lang/Object;)

I really don't know if this is a bug of r2dbc but it happens with spring data when I try to save a very simple instance:

java.lang.AbstractMethodError: Receiver class io.r2dbc.h2.H2Statement does not define or inherit an implementation of the resolved method abstract bind(Ljava/lang/Integer;Ljava/lang/Object;)Lio/r2dbc/spi/Statement; of interface io.r2dbc.spi.Statement. at org.springframework.data.r2dbc.function.DefaultDatabaseClient$DefaultTypedInsertSpec.lambda$exchange$4(DefaultDatabaseClient.java:992) ~[spring-data-r2dbc-1.0.0.BUILD-20181030.065337-2.jar:1.0.0.BUILD-SNAPSHOT] at org.springframework.data.r2dbc.function.DefaultDatabaseClient$DefaultTypedInsertSpec.lambda$exchange$5(DefaultDatabaseClient.java:1002) ~[spring-data-r2dbc-1.0.0.BUILD-20181030.065337-2.jar:1.0.0.BUILD-SNAPSHOT] at org.springframework.data.r2dbc.function.DefaultSqlResult$1.apply(DefaultSqlResult.java:54) ~[spring-data-r2dbc-1.0.0.BUILD-20181030.065337-2.jar:1.0.0.BUILD-SNAPSHOT] at org.springframework.data.r2dbc.function.DefaultSqlResult$1.apply(DefaultSqlResult.java:51) ~[spring-data-r2dbc-1.0.0.BUILD-20181030.065337-2.jar:1.0.0.BUILD-SNAPSHOT] at org.springframework.data.r2dbc.function.DefaultDatabaseClient.doInConnectionMany(DefaultDatabaseClient.java:1016) ~[spring-data-r2dbc-1.0.0.BUILD-20181030.065337-2.jar:1.0.0.BUILD-SNAPSHOT] at org.springframework.data.r2dbc.function.DefaultDatabaseClient.lambda$inConnectionMany$2(DefaultDatabaseClient.java:160) ~[spring-data-r2dbc-1.0.0.BUILD-20181030.065337-2.jar:1.0.0.BUILD-SNAPSHOT]

is this a problem with the current snapshot releases?

Any hint is very welcome :)

Drop oracle-java8-installer from TravisCI build

Oracle constantly keeps changing Java 8 download paths which breaks the build. We rather fall back to an older JDK instead of being affected by broken builds caused due to external infrastructure changes.

Add support to write simple type collections as arrays

Postgres supports ARRAY columns that allow storing multiple values in a field. #22 allows reading these values. We need a possibility how to store these. The assumption for Collection-typed fields is that these values are stored using relations and not within a single column.

java.lang.NoSuchMethodError

Hi guys,
I'm using compile group: 'org.springframework.data', name: 'spring-data-r2dbc', version: '1.0.0.M1'
What I done is:
@Override public Flux<T> findAll() { return databaseClient.select().from(entity.getJavaType()).fetch().all(); }

From ReactiveCrudRepository
Here is a trace:

2019-01-21 17:30:09.743 ERROR 2353 --- [-server-epoll-6] r.i.n.c.ChannelOperations                : 

java.lang.NoSuchMethodError: reactor.core.publisher.Flux.usingWhen(Lorg/reactivestreams/Publisher;Ljava/util/function/Function;Ljava/util/function/Function;Ljava/util/function/Function;Ljava/util/function/Function;)Lreactor/core/publisher/Flux;
	at org.springframework.data.r2dbc.function.DefaultDatabaseClient.inConnectionMany(DefaultDatabaseClient.java:155) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
	at org.springframework.data.r2dbc.function.DefaultFetchSpec.all(DefaultFetchSpec.java:75) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
	at org.springframework.data.r2dbc.function.DefaultSqlResult.all(DefaultSqlResult.java:141) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
	at org.springframework.data.r2dbc.repository.support.SimpleR2dbcRepository.findAll(SimpleR2dbcRepository.java:175) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:629) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:593) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.9.RELEASE.jar:2.0.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at com.sun.proxy.$Proxy83.findAll(Unknown Source) ~[?:?]
	at com.arm.hma.simulator.controller.DeviceDirectoryController.getDevices(DeviceDirectoryController.java:29) ~[bin/:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
	at org.springframework.web.reactive.result.method.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:243) ~[spring-webflux-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at org.springframework.web.reactive.result.method.InvocableHandlerMethod.lambda$invoke$0(InvocableHandlerMethod.java:138) ~[spring-webflux-5.0.8.RELEASE.jar:5.0.8.RELEASE]
	at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:141) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:153) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:271) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:803) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:115) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:1640) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:156) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1454) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1328) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:418) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:210) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:140) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:64) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3080) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:70) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.1.8.RELEASE.jar:3.1.8.RELEASE]
	at reactor.ipc.netty.channel.ChannelOperations.applyHandler(ChannelOperations.java:380) ~[reactor-netty-0.7.8.RELEASE.jar:0.7.8.RELEASE]
	at reactor.ipc.netty.http.server.HttpServerOperations.onHandlerStart(HttpServerOperations.java:398) ~[reactor-netty-0.7.8.RELEASE.jar:0.7.8.RELEASE]
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) [netty-common-4.1.27.Final.jar:4.1.27.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) [netty-common-4.1.27.Final.jar:4.1.27.Final]
	at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:322) [netty-transport-native-epoll-4.1.27.Final-linux-x86_64.jar:4.1.27.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) [netty-common-4.1.27.Final.jar:4.1.27.Final]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_201]

How to use transaction with repository?

As transaction doc said, we can use transaction with calling the APIs of TransactionalDatabaseClient, but how can I do it if I want to use repository?

What a potential solution I thought to approach my goal (using transaction for multiple repositories' operators) is:

transactionalDatabaseClient.beginTransaction();
userRepository.save(user);
passwordHistoryRepository.save(user.getPassword());
transactionalDatabaseClient.commitTransaction();

But it won't work, right? because in the example, transaction is implemented by same dataClient, but Repository is using another client, How can I customize the dataClient in Repository?

And I checked the detail code, transaction is implemented based on Connection, to approach my goal, how can I let dataClinet and Repository use same Connection?

Add named parameter support

We should introduce named parameter support for DatabaseClient and repositories using a uniform naming pattern to decouple from vendor-specific bind marker syntax.

Right now, we need to stick to vendor-specific bind markers if we want to bind parameters to a statement. This makes statements non-portable.

exchange() should allow to deal with DROP or CREATE requests

Like exchange() provides a generic way to deal with requests in WebClient even those with no body, I would expect DatabaseClient variant to do the same. Maybe by providing in SqlResult methods suitable to deal with request with no rows like DROP or CREATE ones.

How to enable Repository inerface in data-r2dbc project

I created a sample project to demo spring-data-r2dbc, check it from my github account.

https://github.com/hantsy/spring-reactive-sample/tree/master/data-r2dbc

For other Spring data projects, there is a @EnableXXX annotation for this purpose, but I can not find such one in Spring Data R2dbc, my sample failed when it is started.

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'postController' defined in file [E:\hantsylabs\spring-reactive-sample\data-r2dbc\target\classes\com\example\demo\PostController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.PostRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Move Conversion-related functionality to MappingR2dbcConverter

Currently, we have conversion code laid out in EntityRowMapper (entity reading), DefaultReactiveDataAccessStrategy (entity to SettableValue conversion). We should pull methods into a single MappingR2dbcConverter to keep conversion code closely together.

Cleanup pom.xml and upgrade dependencies

  • Remove dependency management for Surefire and Dependency plugins
  • Upgrade to latest Postgres and H2 drivers
  • Upgrade to latest testcontainers

Currently, dependencies cause test failures on Java 9 and higher.

Preserving order on multiple inserts

What are the guarantees in terms of insertion order for R2dbcRepository#saveAll for new items? Some experiments I have been playing around with seem to show that the insertion order is not honored, which makes sense since SimpleR2dbcRepository#saveAll is just a flatMap built on SimpleR2dbcRepository#save, and the latter queues an asynchronous job on the TcpResources pool of Reactor-Netty.

While our-of-order updates is pretty much a non-issue in my experience, not honoring the insertion order is very confusing when the database is generating sequential primary keys.

For reference, #7 enhances the tests to show sporadic failures due to the insertion order not been deterministic.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.