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.