楔子:当然,世上有很多优秀的女性,我也会被她们吸引。这对男人来说是理所当然的。但目光被吸引和内心被吸引是截然不同的。- 东野圭吾《黎明之街》
1.今日书签
在一些应用场景中,可能需要连接多个不同的数据库,例如连接不同的数据库服务器或者连接主从数据库。这段代码就是为了实现这种多数据源的配置。
具体来说,这个类包含两个内部静态类:
- MyBatisDataSourceConfiguration4XMei: 这个类配置了第一个数据源,即 “xmei” 数据源。它使用了
@Primary 注解来指示这是默认的主数据源。这个数据源配置了一个 Druid 数据源,并配置了与该数据源相关的
SqlSessionFactory、事务管理器(DataSourceTransactionManager)和
SqlSessionTemplate。@MapperScan 注解用于指示需要扫描哪些包下的 Mapper 接口,并使用特定的
SqlSessionFactory。它还定义了 Mapper XML 文件的路径,以及事务管理和 SqlSessionTemplate。 - MyBatisDataSourceConfiguration4XWei: 这个类配置了第二个数据源,即 “xwei” 数据源。它没有使用
@Primary 注解,因此不是默认的主数据源。它使用了 @Qualifier 注解来指定特定的 Bean
名称,用于解决多个数据源的冲突。与第一个数据源类似,它配置了一个 Druid 数据源,并定义了与该数据源相关的
SqlSessionFactory、事务管理器和 SqlSessionTemplate。
2.多数据源
使用 Service、Mapper、XML 所在包路径区分默认数据源 与 第二数据源。
直接看代码:
/**
* 多数据源接入
* dataSource4XMei 为 xmei 库,为默认数据源,正常使用,此处以外无其它配置
* dataSource4XWei 为 xwei 库,为第二数据源,正常使用,此处以外无其它配置
*/
@Configuration
public class MyBatisConfiguration {
/**
* 配置 SpringBoot 默认数据源,一般配置为主数据库,此为 xmei
*/
@Configuration
@MapperScan(basePackages = {"com.cw.tan.xmei.persistence.*"}, sqlSessionFactoryRef = "sqlSessionFactory4XMei")
protected static class MyBatisDataSourceConfiguration4XMei {
@Bean
@Primary
@ConfigurationProperties("spring.datasource.druid.xmei")
public DataSource dataSource4XMei() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public SqlSessionFactory sqlSessionFactory4XMei(DataSource dataSource4XMei) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource4XMei);
sqlSessionFactoryBean.setMapperLocations(this.resolveMapperLocations());
return sqlSessionFactoryBean.getObject();
}
private Resource[] resolveMapperLocations() {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<String> mapperLocations = new ArrayList<>();
mapperLocations.add("classpath*:com/cw/tan/xmei/persistence/**/*.xml");
List<Resource> resources = new ArrayList();
if (!CollectionUtils.isEmpty(mapperLocations)) {
for (String mapperLocation : mapperLocations) {
try {
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
// ignore
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
/**
* 配置事务管理
*/
@Bean
@Primary
public DataSourceTransactionManager transactionManager4XMei(DataSource dataSource4XMei) {
return new DataSourceTransactionManager(dataSource4XMei);
}
@Bean
@Primary
public SqlSessionTemplate sqlSessionTemplate4XMei(SqlSessionFactory sqlSessionFactory4XMei) {
return new SqlSessionTemplate(sqlSessionFactory4XMei);
}
}
/**
* 配置第二数据源,注意 mapper 扫描路径和上面的区分开
*/
@Configuration
@MapperScan(basePackages = {"com.cw.tan.xwei.log.mapper","com.cw.tan.xwei.sms.mapper", "com.cw.tan.xwei.job.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory4XWei")
protected static class MyBatisDataSourceConfiguration4XWei {
@Bean(name = "dataSource4XWei")
@ConfigurationProperties("spring.datasource.druid.xwei")
public DataSource dataSource4XWei() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "sqlSessionFactory4XWei")
public SqlSessionFactory sqlSessionFactory4XWei(@Qualifier("dataSource4XWei") DataSource dataSource4XWei) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource4XWei);
sqlSessionFactoryBean.setMapperLocations(this.resolveMapperLocations());
return sqlSessionFactoryBean.getObject();
}
private Resource[] resolveMapperLocations() {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
List<String> mapperLocations = new ArrayList<>();
mapperLocations.add("classpath*:com/cw/tan/xwei/log/**/*.xml");
mapperLocations.add("classpath*:com/cw/tan/xwei/sms/**/*.xml");
mapperLocations.add("classpath*:com/cw/tan/xwei/job/**/*.xml");
List<Resource> resources = new ArrayList<>();
if (!CollectionUtils.isEmpty(mapperLocations)) {
mapperLocations.forEach(mapperLocation -> {
try {
Resource[] mappers = resourcePatternResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
// ignore
}
});
}
return resources.toArray(new Resource[resources.size()]);
}
@Bean(name = "transactionManager4XWei")
public DataSourceTransactionManager transactionManager4XWei(@Qualifier("dataSource4XWei") DataSource dataSource4XWei) {
return new DataSourceTransactionManager(dataSource4XWei);
}
@Bean(name = "sqlSessionTemplate4XWei")
public SqlSessionTemplate sqlSessionTemplate4XWei(@Qualifier("sqlSessionFactory4XWei") SqlSessionFactory sqlSessionFactory4XWei) {
return new SqlSessionTemplate(sqlSessionFactory4XWei);
}
}
}
注意:上述配置,请确认自己的默认数据源、第二数据源对应Service、DAO文件所在的包路径,如果路径指向不对,可能会出现以下异常:
2023-08-17 16:09:33.981 [TID:] [main] WARN AnnotationConfigServletWebServerApplicationContext.refresh():559 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘dataDataSyncController’: Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.cw.tan.xwei.job.IDataSyncService’ available: expected single matching bean but found 2: dataSyncServiceImpl,IDataSyncService
3.配置中心
druid 配置
第一数据源,即 “xmei” 数据源的 Apollo 配置:
spring.datasource.druid.xmei.url = jdbc:mysql://mysql.test.cw.com:3306/xmei?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false
spring.datasource.druid.xmei.username = xmei
spring.datasource.druid.xmei.password = 12345678
spring.datasource.druid.xmei.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.druid.xmei.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.xmei.defaultAutoCommit = true
spring.datasource.druid.xmei.initialSize = 10
spring.datasource.druid.xmei.minIdle = 10
spring.datasource.druid.xmei.maxActive = 50
spring.datasource.druid.xmei.maxWait = 1000
spring.datasource.druid.xmei.validationQuery = SELECT 1
spring.datasource.druid.xmei.testWhileIdle = true
spring.datasource.druid.xmei.testOnBorrow = true
spring.datasource.druid.xmei.testOnReturn = false
spring.datasource.druid.xmei.filters = config,stat,wall
spring.datasource.druid.xmei.filter.stat.slow-sql-millis = 1000
第一数据源,即 “xwei” 数据源的 Apollo 配置:
spring.datasource.druid.xwei.url = jdbc:mysql://mysql.test.cw.com:3306/xwei?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false
spring.datasource.druid.xwei.username = bi_hs
spring.datasource.druid.xwei.password = d41d8cd98f00b204
spring.datasource.druid.xwei.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.druid.xwei.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.xwei.defaultAutoCommit = true
spring.datasource.druid.xwei.initialSize = 10
spring.datasource.druid.xwei.minIdle = 10
spring.datasource.druid.xwei.maxActive = 50
spring.datasource.druid.xwei.maxWait = 1000
spring.datasource.druid.xwei.validationQuery = SELECT 1
spring.datasource.druid.xwei.testWhileIdle = true
spring.datasource.druid.xwei.testOnBorrow = true
spring.datasource.druid.xwei.testOnReturn = false
spring.datasource.druid.xwei.filters = config,stat,wall
spring.datasource.druid.xwei.filter.stat.slow-sql-millis = 1000
application.yml 配置
spring:
application:
name: x-cw
profiles:
active: test
apollo:
bootstrap:
enabled: true
namespaces: application.yml,redis.yml,db_xmei.properties,db_xwei.properties
4.总结
这段代码通过两个内部静态类分别配置了两个不同的数据源(xmei 和 xwei)。每个数据源配置了对应的 Druid 数据源、SqlSessionFactory、事务管理器和 SqlSessionTemplate。这种多数据源配置适用于需要访问多个不同数据库的场景,如在一个系统中同时连接多个数据库来进行不同的操作,比如主数据库和日志数据库、数据库与业务库数据同步等。
如果还需要扩展更多数据源,则可将上述 第二数据源配置 进行复制粘贴,然后做相应名称、包路径的修改,再加上第N数据源配置即可。