Affects: 5.3.29
I have a Spring project that uses Spring Data R2DBC with Oracle driver, I created the required ConnectionFactory
and ReactiveTransactionManager
and I use @Transactional
in the required methods. Spring correctly uses ReactiveTransactionManager
instead of PlatformTransactionManager
to manage these Spring-managed transactions and there is no problem. But it is different in tests, as we know if @Transactional
is used in test cases, it is considered as Test-managed transactions and will be automatically rolled back after completion of the test.
although ConnectionFactory
and ReactiveTransactionManager
are configured correctly, Spring tries to use PlatformTransactionManager
instead of ReactiveTransactionManager
for Test-managed transactions. As a result, the following error is given:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'myReactiveTransactionManager' is expected to be of type 'org.springframework.transaction.PlatformTransactionManager' but was actually of type 'org.springframework.r2dbc.connection.R2dbcTransactionManager'
After this issue, I searched a little in the spring-test
code, and by examining the org.springframework.test.context.transaction.TransactionalTestExecutionListener
class, I came to the conclusion that Spring only supports PlatformTransactionManager
in the test environment.
Is my conclusion correct, and we should wait for the support of ReactiveTransactionManager
in new versions of spring-test, or is there a problem with my configuration and usage?
This is similar to my ConnectionFactory
and ReactiveTransactionManager
configuration in the code environment:
@Configuration
@EnableR2dbcRepositories
public class OracleR2dbcConfig extends AbstractR2dbcConfiguration {
public static final String MY_R2DBC_TRANSACTION_MANAGER = "myReactiveTransactionManager";
public static final String MY_R2DBC_CONNECTION_FACTORY = "myReactiveConnectionFactory";
@Bean(name = MY_R2DBC_CONNECTION_FACTORY)
@Override
public @NonNull ConnectionFactory connectionFactory() {
ConnectionFactoryOptions options = ConnectionFactoryOptions.builder()
.option(HOST, "localhost")
.option(PORT, 1521)
.option(USER, "user")
.option(PASSWORD, "password")
.build();
return new OracleConnectionFactoryProviderImpl().create(options);
}
@Bean(name = MY_R2DBC_TRANSACTION_MANAGER)
public ReactiveTransactionManager myTransactionManager(@Qualifier(MY_R2DBC_CONNECTION_FACTORY) ConnectionFactory connectionFactory) {
return new R2dbcTransactionManager(connectionFactory);
}
}
and this is ConnectionFactory
and ReactiveTransactionManager
configuration in the test environment:
@Configuration
@EnableR2dbcRepositories
public class H2R2dbcConfig extends AbstractR2dbcConfiguration {
public static final String MY_R2DBC_TRANSACTION_MANAGER = "myReactiveTransactionManager";
public static final String MY_R2DBC_CONNECTION_FACTORY = "myReactiveConnectionFactory";
@Bean(name = MY_R2DBC_CONNECTION_FACTORY)
@Override
public @NonNull ConnectionFactory connectionFactory() {
return ConnectionFactories.get("r2dbc:h2:mem:///testdb?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
}
@Bean(name = MY_R2DBC_TRANSACTION_MANAGER)
public ReactiveTransactionManager myTransactionManager(@Qualifier(MY_R2DBC_CONNECTION_FACTORY) ConnectionFactory connectionFactory) {
return new R2dbcTransactionManager(connectionFactory);
}
}
Comment From: sbrannen
Hi @AliAkbarMoeini,
Thanks for the detailed report, and congratulations on reporting your first issue for the Spring Framework.
This has been raised before, so I'm closing this as a:
- Duplicate of #24226
Feel free to participate in the discussion in that issue.