Spring多数据源管理方案
基于Spring的AbstractRoutingDataSource实现多数据源
数据库连接配置
spring:
application:
name: dynamic-source
datasource:
datasource1:
jdbc-url: jdbc:mysql://localhost:3306/cloud-demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
initialSize: 1
maxActive: 20
minIdle: 1
maxWait: 60000
datasource2:
jdbc-url: jdbc:mysql://localhost:3306/foodie_dev?useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
initialSize: 1
maxActive: 20
minIdle: 1
maxWait: 60000
数据源配置
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource1")
public DataSource dataSource1() {
// 根据配置 创建数据源实例
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource2")
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
}
继承AbstractRoutingDataSource,实现数据源切换逻辑
@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
public static ThreadLocal<String> dataSourceKey = new ThreadLocal<>();
@Autowired
private DataSource dataSource1;
@Autowired
private DataSource dataSource2;
/**
* 决定使用哪个数据源之前需要调用这个方法来设置
*/
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get();
}
@Override
public void afterPropertiesSet() {
HashMap<Object, Object> targetDataSource = new HashMap<>();
targetDataSource.put("W", dataSource1);
targetDataSource.put("R", dataSource2);
//设置数据源
super.setTargetDataSources(targetDataSource);
//设置默认数据源
super.setDefaultTargetDataSource(dataSource1);
super.afterPropertiesSet();
}
}
在进行数据库操作时,切换到指定的数据源
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private AccountMapper accountManager;
@RequestMapping("/account")
public String selectAccount() {
//查询clouded-demo数据库的account表
DynamicDataSource.dataSourceKey.set("W");
Account account = accountManager.selectByPrimaryKey(1);
return account.toString();
}
@Autowired
private BookMapper bookMapper;
@RequestMapping("/book")
public String selectBook() {
//查询foodie_dev数据库的book表
DynamicDataSource.dataSourceKey.set("R");
Book book = bookMapper.selectByPrimaryKey(1);
return book.toString();
}
}
基于Mybatis实现多数据源
基于Mybatis实现多数据源管理,需要自己给每个数据源分别注册DataSource、SqlSessionFactory、
ataSourceTransactionManager
注册数据源1
@Configuration
@MapperScan(basePackages = "com.example.common.dao.w", sqlSessionFactoryRef = "wSqlSessionFactory")
public class WDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource1")
public DataSource wDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public SqlSessionFactory wSqlSessionFactory(@Qualifier ("wDataSource") DataSource wDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
//指定这个数据源要使用的mapper文件的位置
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:mappers/w/*.xml"));
sqlSessionFactoryBean.setDataSource(wDataSource);
return sqlSessionFactoryBean.getObject();
}
@Bean
public DataSourceTransactionManager wDataSourceTransactionManager(@Qualifier ("wDataSource") DataSource wDataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(wDataSource);
return transactionManager;
}
}
注册数据源2
@Configuration
@MapperScan(basePackages = "com.example.common.dao.r", sqlSessionFactoryRef = "rSqlSessionFactory")
public class RDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource2")
public DataSource rDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory rSqlSessionFactory(@Qualifier("rDataSource") DataSource rDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:mappers/r/*.xml"));
sqlSessionFactoryBean.setDataSource(rDataSource);
return sqlSessionFactoryBean.getObject();
}
@Bean
public DataSourceTransactionManager rDataSourceTransactionManager(@Qualifier("rDataSource") DataSource rDataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(rDataSource);
return transactionManager;
}
}
基于Mybatis实现的多数据源管理不需要在进行数据库操作时切换数据源,因为已经给不同的数据源维护了不同的SqlSessionFactory等组件。
使用dynamic-datasource框架
多数据源下的事务处理
在多数据源下,事务的处理成为了一个问题。因为可能需要对不同的库进行操作,那么这个时候就需要考虑事务问题了。如果一个业务中对两个库进行了操作,那么对这两个库的操作必须要同时失败或者同时成功。