Spring Boot 和 Spring JDBC 多数据源
Posted
技术标签:
【中文标题】Spring Boot 和 Spring JDBC 多数据源【英文标题】:SpringBoot and SpringJDBC multiple datasources 【发布时间】:2016-09-14 05:39:21 【问题描述】:我试图在我的 SpringBoot 应用程序中使用两个数据源,但无法让第二个数据源自动装配。我尝试了很多东西,但这是我最接近的:
我的 Yaml 文件:
spring:
first-datasource:
url: MyURLString1
username: User
password: Password
driver-class-name: oracle.jdbc.OracleDriver
second-datasource:
url: MyURLString2
username: User
password: Password
driver-class-name: oracle.jdbc.OracleDriver
我的应用类:
@SpringBootApplication
public class MyApplication
public static void main(String[] args)
SpringApplication.run(MyApplication.class, args);
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.first-datasource")
public DataSource firstDataSource()
return DataSourceBuilder.create().build();
@Bean
@ConfigurationProperties(prefix = "spring.second-datasource")
public DataSource secondDataSource()
return DataSourceBuilder.create().build();
最后是我的 DAO:
@Repository
public class MyDao
private static final String FIRST_SELECT = "select * from SomeTableInDB1";
private static final String SECOND_SELECT = "select * from AnotherTableInDB2";
@Autowired
private JdbcTemplate firstJdbcTemplate;
@Autowired
@Qualifier("secondDataSource")
private JdbcTemplate secondJdbcTemplate;
List<DB1Entity> getDB1Entity(Long id)
return firstJdbcTemplate.query(FIRST_SELECT, new Object[] id, new BeanPropertyRowMapper(DB1Entity.class));
List<DB2Entity> getDB2Entity(Long id)
return secondJdbcTemplate.query(SECOND_SELECT, new Object[] id, new BeanPropertyRowMapper(DB2Entity.class));
这是迄今为止我最接近的一次。我说它是最接近的,因为如果我删除了@Qualifier,那么我的两个 dao 方法实际上都可以工作,假设 SECOND_SELECT 语句对于我的 DB1 是有效的 SQL。一旦我为我的非主要数据源输入了@Qualifier,我就会收到一个自动装配错误,因为 Spring 需要一个 Datasouce 对象,而不是 JdbcTemplate 对象。这对我来说很奇怪,因为它确实适用于主数据源。
这是我的错误:
无法自动装配字段:private org.springframework.jdbc.core.JdbcTemplate org.my.classpath.secondJdbcTemplate;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency: 预期至少有 1 个 bean 有资格作为此依赖项的自动装配候选者。依赖注解:@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=secondDataSource)
【问题讨论】:
您创建类型为 DataSource 但 Autowire JdbcTemplate 的 bean。你可能应该有这样的东西private JdbcTemplate jdbcTemplate1; private JdbcTemplate jdbcTemplate2; @Autowired @Qualifier("firstDataSource") public void setDataSource(DataSource dataSource) this.jdbcTemplate1 = new JdbcTemplate(dataSource); @Autowired @Qualifier("secondDataSource") public void setDataSource(DataSource dataSource) this.jdbcTemplate2 = new JdbcTemplate(dataSource);
我曾尝试过与此几乎相同的方法,但收到有关空 URL 的错误。我一定是打错了东西,因为我复制了你的代码并且它有效。谢谢。我敢肯定这很愚蠢。
@lenach87 这是正确的解决方案,我认为这个问题很好。发表一个答案,我会将其标记为正确的。
我很高兴它有帮助!我会把它作为答案发布,谢谢
【参考方案1】:
就我而言,按照@Aman Tuladhar 的回答,工作方式如下: (Spring Boot 2.1.3.RELEASE)
@Configuration
public class JDBCConfig
@Bean("first-datasource")
public JdbcTemplate paymentsJDBCTemplate(@Qualifier("first-db") DataSource paymentsDataSource)
return new JdbcTemplate(paymentsDataSource);
@Bean("second-datasource")
public JdbcTemplate parametersJDBCTemplate(@Qualifier("second-db") DataSource paramsDataSource)
return new JdbcTemplate(paramsDataSource);
@Bean("first-db")
public DataSource paymentsDataSource(Environment env)
return buildDataSource(env, "first");
@Bean("second-db")
public DataSource paramsDataSource(Environment env)
return buildDataSource(env, "second");
private DataSource buildDataSource(Environment env, String prop)
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring."+prop+"-datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring."+prop+"-datasource.url"));
dataSource.setUsername(env.getProperty("spring."+prop+"-datasource.username"));
dataSource.setPassword(env.getProperty("spring."+prop+"-datasource.password"));
return dataSource;
...并像这样使用:
@Autowired @Qualifier("first-datasource")
private JdbcTemplate jdbcTemplate1;
@Autowired @Qualifier("second-datasource")
private JdbcTemplate jdbcTemplate2;
...应用程序.yml:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: $DATABASE_1_URL
username: $DATABASE_1_USERNAME
password: $DATABASE_1_PASSWORD
second-datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: $DATABASE_2_URL
username: $DATABASE_2_USERNAME
password: $DATABASE_2_PASSWORD
【讨论】:
【参考方案2】:这里还提供了另一种让我困惑了几天的“不工作”情况:
在 Springboot 应用程序中配置两个相同类型的数据源时,@Qualifier
无法按预期工作以获取正确的 bean。它的行为就像 Spring 框架无法识别一样。
原因是在使用 @SpringbootApplication
注释时,其中包含 @EnableAutoConfiguration
注释,在 Springboot 中,它将自动配置它为用户提供的数据源。
这会严重影响@Qualifier
的行为。
【讨论】:
【参考方案3】:理想情况下,但不是强制要求,应将其中一个数据源标记为 PRIMARY,以使大多数通过 Annotations 进行的默认接线工作。此外,我们需要为每个数据源分别创建 TransactionManagers,否则 Spring 将不知道如何执行 Transactions。以下是如何完成此操作的完整示例
@Primary
@Bean(name = "dataSource")
@ConfigurationProperties(prefix="datasource.mysql")
public DataSource dataSource()
return DataSourceBuilder.create().build();
@Primary
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource)
return new DataSourceTransactionManager();
@Bean(name = "postGresDataSource")
@ConfigurationProperties(prefix="datasource.postgres")
public DataSource postgresDataSource()
return DataSourceBuilder.create().build();
@Bean(name = "postGresTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("postGresDataSource") DataSource dataSource)
return new DataSourceTransactionManager();
@Transactional(transactionManager="postGresTransactionManager")
public void createCustomer(Customer cust)
customerDAO.create(cust);
// specifying a transactionManager attribute is optional if we
// want to use the default transactionManager since we
// already marked one of the TM above with @Primary
@Transactional
public void createOrder(Order order)
orderDAO.create(order);
希望这会有所帮助。
【讨论】:
【参考方案4】:您创建了 DataSource
类型的 bean,但尝试使用不匹配的 Autowire JdbcTemplate。你可能应该有这样的东西
private JdbcTemplate jdbcTemplate1;
private JdbcTemplate jdbcTemplate2;
@Autowired
@Qualifier("firstDataSource")
public void setDataSource(DataSource dataSource)
this.jdbcTemplate1=new JdbcTemplate(dataSource);
@Autowired
@Qualifier("secondDataSource")
public void setDataSource(DataSource dataSource)
this.jdbcTemplate2=new JdbcTemplate(dataSource);
【讨论】:
以上是关于Spring Boot 和 Spring JDBC 多数据源的主要内容,如果未能解决你的问题,请参考以下文章
spring boot: spring boot+jdbctemplate+sql server
Spring Boot 和 Spring JDBC 多数据源
Spring-Boot:如何设置 JDBC 池属性,例如最大连接数?