Hel
Hel

Reputation: 305

NoUniqueBeanDefinitionException when multiple datasources in Spring Boot and Mybatis project

When configuring multiple datasources in Spring Boot and Mybatis project, following Exception occurs:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available: expected single matching bean but found 2: primaryTx,secondTx at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:384) ~[spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272) ~[spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at com.sun.proxy.$Proxy86.findByDomain(Unknown Source) ~[na:na]

start of project

@SpringBootApplication( exclude = {
        DataSourceAutoConfiguration.class, 
        DataSourceTransactionManagerAutoConfiguration.class
})
@EnableTransactionManagement
public class BookSystemApplication {
}

datasource configuration

@Configuration
public class DataSourceConfig {
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource secondDataSource() {
        return DataSourceBuilder.create().build();
    }
}

Transaction

@Configuration
public class TransactionConfig {
    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primary;

    @Autowired
    @Qualifier("secondDataSource")
    private DataSource second;

    @Bean(name="primaryTx")
    public PlatformTransactionManager primaryTransaction() {
        return new DataSourceTransactionManager(primary);
    }

    @Bean(name="secondTx")
    public PlatformTransactionManager secondTransaction() {
        return new DataSourceTransactionManager(second);
    }
}

Upvotes: 1

Views: 3058

Answers (2)

hua
hua

Reputation: 1

First,thanks √ answer,it solved my problem perfectly.

And I can offer another way of thinking.Unnecessary @Primary to someone,you can define like @Transactional("primaryTx") in your service.

like this:

    @Override
    @Transactional("primaryTx")
    public Test update() {
        Test entity = new Test();
        entity.setId(1L);
        entity.setPhone("19900000050");
        return testRepository.save(entity);
    }

Upvotes: 0

cнŝdk
cнŝdk

Reputation: 32145

The problem here is that you are defining two beans as datasource and two beans as TransactionManager but you didn't specify which one of them is the primary one, this won't work because Spring needs one datasource bean and one TransactionManager bean to be defined as primary if more than one are defined.

What you should do here is to define, one of your datasources beans and one of your TransactionManager beans as Primary, so that Spring can run correctly, to do so you will need to use @Primary annotation.

@Bean(name = "primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
}

Please refer to the Spring's Configure two datasources section from the Documentation.

Upvotes: 2

Related Questions