【问题标题】:Spring boot - Issue with multiple DataSourceSpring boot - 多个数据源的问题
【发布时间】:2023-03-20 04:38:01
【问题描述】:

我有一个 ReST 服务需要从两个不同的数据库(Oracle 和 MySQL)获取数据并将这些数据合并到响应中。

我有以下配置。

DB 1 的配置:

@Configuration 
public class DbConfig_DB1{

    @Bean(name="siebelDataSource")
    public EmbeddedDatabase siebelDataSource(){
        return new EmbeddedDatabaseBuilder().
                setType(EmbeddedDatabaseType.H2).
                addScript("schema.sql").
                addScript("test-data.sql").
                build();

    }

    @Autowired
    @Qualifier("siebelDataSource")
    @Bean(name = "siebelJdbcTemplate") 
    public JdbcTemplate siebelJdbcTemplate(DataSource siebelDataSource) { 
        return new JdbcTemplate(siebelDataSource); 
    } 
}

DB2 的配置:

@Configuration 
public class DbConfig_DB2{      
    @Bean(name="brmDataSource")
    public EmbeddedDatabase brmDataSource(){
        return new EmbeddedDatabaseBuilder().
                setType(EmbeddedDatabaseType.H2).
                addScript("schema-1.sql").
                addScript("test-data-1.sql").
                build();

    }

    @Autowired
    @Qualifier("brmDataSource")
    @Bean(name = "brmJdbcTemplate") 
    public JdbcTemplate brmJdbcTemplate(DataSource brmDataSource) { 
        return new JdbcTemplate(brmDataSource); 
    } 
} 

数据访问:

@Repository
public class SiebelDataAccess {
    protected final Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier("siebelJdbcTemplate")
    protected JdbcTemplate jdbc;

    public String getEmpName(Integer id) {

        System.out.println(jdbc.queryForObject("select count(*) from employee", Integer.class));

        Object[] parameters = new Object[] { id };
        String name = jdbc.queryForObject(
                "select name from employee where id = ?", parameters,
                String.class);
        return name;
    }

}

由于出现以下错误,我无法启动应用程序:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration.dataSource; 

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: brmDataSource,siebelDataSource

问题在于上下文中有两个 DataSource bean。如何解决?

【问题讨论】:

    标签: spring spring-boot autowired spring-jdbc jdbctemplate


    【解决方案1】:

    您可以将其中一个标记为@Primary,以便事务管理器的 Spring Boot 自动配置知道选择哪一个。如果您需要同时管理交易,那么恐怕您必须明确设置交易管理。

    请参考Spring Boot documentation

    创建多个数据源的工作方式与创建第一个数据源相同。如果您使用 JDBC 或 JPA 的默认自动配置,您可能希望将其中一个标记为 @Primary(然后任何 @Autowired 注入都会选择该配置)。

    【讨论】:

    • 所以为了测试我为两个 H2 实例运行了相同的 sql 模式和内容。显然它们被覆盖了。有没有办法在内存中有两个 H2 实例?
    • 您是否尝试在EmbeddedDatabaseBuilder 上致电setName()?否则,它在两种情况下都使用相同的数据库名称并针对相同的数据库执行架构脚本。