Транзакции, Spring Boot Starter JDB C & R2DBC - PullRequest
0 голосов
/ 25 марта 2020

Я пытаюсь перенести проект Spring Boot версии 2.3.0.M3, который использовал шаблон JDB C, в R2DB C. В проекте также используется Liquibase, поэтому я не могу полностью избавиться от JDB C. У меня в проекте есть зависимости spring-boot-starter-data-r2db c и spring-boot-starter-jdb c, с которыми я получаю следующее исключение при попытке запустить один из моих тестов:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.TransactionManager' available: expected single matching bean but found 2: transactionManager,connectionFactoryTransactionManager

    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1180)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:416)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:480)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:335)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
...

Диспетчер bean-компонента connectionFactoryTransaction определяется следующим образом в классе Spring R2dbcTransactionManagerAutoConfiguration:

    @Bean
    @ConditionalOnMissingBean(ReactiveTransactionManager.class)
    public R2dbcTransactionManager connectionFactoryTransactionManager(ConnectionFactory connectionFactory) {
        return new R2dbcTransactionManager(connectionFactory);
    }

Транзитный компонент Bean-компонента определяется следующим образом в классе Spring DataSourceTransactionManagerAutoConfiguration:

   @Bean
   @ConditionalOnMissingBean(PlatformTransactionManager.class)
   DataSourceTransactionManager transactionManager(DataSource dataSource,
           ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
       DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
       transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
       return transactionManager;
   }
1009 * Как видно, аннотация @ConditionalOnMissingBean содержит разные типы, которые приведут к созданию экземпляра обоих компонентов. Однако в классе Spring TransactionAspectSupport есть следующая строка кода в методе defineTransactionManager:
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);

Поскольку оба типа менеджера транзакций, DataSourceTransactionManager и R2dbcTransactionManager, реализуют интерфейс TransactionManager, оба компонента менеджера транзакций работают как приведенное выше совпадение и возникнет ошибка.

Сейчас я обращаюсь, чтобы узнать, есть ли кто-нибудь, кому удалось решить или обойти эту проблему? Заранее спасибо!

1 Ответ

0 голосов
/ 25 марта 2020

Вдохновленный ответом М. Дейнума (спасибо!), Я применил следующие шаги к своему проекту, и тест, который не удался раньше, теперь успешно выполняется:

  • Удалите spring-boot-starter- jdb c зависимость.
  • Добавить зависимость к spring-jdb c.
  • Добавить зависимость к HikariCP (com.zaxxer).
  • Добавить spring.liquibase свойства user и password (у меня уже были свойства url и change-log).
  • Удалите все свойства spring.datasource (у меня были url и имя-класса-диска).

У меня были определены имя пользователя, пароль и url свойств spring.r2db c, которые мне не нужно было менять.

Обновление: Кроме того, я использовал Testcontainers в тестах и ​​не мог назначить порт stati c. Чтобы иметь возможность настроить порт базы данных на Liquibase, я переопределил имя bean-компонента liquibase типа SpringLiquibase и создал DataSource (не представленный в виде bean-компонента) в методе создания bean-компонента liquibase и установил его для bean-компонента liquibase.

...