使用SpringAbstractRoutingDataSource完成多数据源管理
1.多数据切换原理: 多数据源能进行动态切换的核心就是spring底层提供了AbstractRoutingDataSource类进行数据源路由。我们主要继承这个类,实现里面的方法即可实现。
∴主要是实现方法:determineCurrentLookupKey(),而此方法只需要返回一个数据库的名称即可。 ∴我们核心的是有一个类来管理数据源的线程池,这个类才是动态数据源的核心处理类。还有就是使用aop在方法前进行数据源的切换。
2.加入多数据源配置: 以dev环境为例,加入目前比较常用的4个库——base、erp、order、finance。
多数据源配置-dev spring: aop: auto: true proxy-target-class: true datasource: type: com.alibaba.druid.pool.DruidDataSource druid: # base库 db-base: url: jdbc:mysql://192.168.3.228:3306/dxh_base?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true username: dxh password: Dxh2017$$ driver-class-name: com.mysql.jdbc.Driver initialSize: 5 minIdle: 5 max-active: 200 max-wait: 10000 test-on-borrow: false test-on-return: false time-between-eviction-runs-millis: 15000 default-auto-commit: true min-evictable-idle-time-millis: 30000 use-global-data-source-stat: true filter: stat: enabled: false db-type: mysql log-slow-sql: true slow-sql-millis: 2 slf4j: data-source-log-enabled: true data-source-logger-name: DRUID statement-executable-sql-log-enable: true statement-logger-name: DRUID
db-erp: url: jdbc:mysql://192.168.3.228:3306/dxh_erp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
username: dxh
password: Dxh2017$$
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
max-active: 200
max-wait: 10000
test-on-borrow: false
test-on-return: false
time-between-eviction-runs-millis: 15000
default-auto-commit: true
min-evictable-idle-time-millis: 30000
use-global-data-source-stat: true
filter:
stat:
enabled: false
db-type: mysql
log-slow-sql: true
slow-sql-millis: 2
slf4j:
data-source-log-enabled: true
data-source-logger-name: DRUID
statement-executable-sql-log-enable: true
statement-logger-name: DRUID
db-order:
url: jdbc:mysql://192.168.3.228:3306/dxh_order?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
username: dxh
password: Dxh2017$$
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
max-active: 200
max-wait: 10000
test-on-borrow: false
test-on-return: false
time-between-eviction-runs-millis: 15000
default-auto-commit: true
min-evictable-idle-time-millis: 30000
use-global-data-source-stat: true
filter:
stat:
enabled: false
db-type: mysql
log-slow-sql: true
slow-sql-millis: 2
slf4j:
data-source-log-enabled: true
data-source-logger-name: DRUID
statement-executable-sql-log-enable: true
statement-logger-name: DRUID
db-finance:
url: jdbc:mysql://192.168.3.228:3306/dxh_finance?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
username: dxh
password: Dxh2017$$
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
max-active: 200
max-wait: 10000
test-on-borrow: false
test-on-return: false
time-between-eviction-runs-millis: 15000
default-auto-commit: true
min-evictable-idle-time-millis: 30000
use-global-data-source-stat: true
filter:
stat:
enabled: false
db-type: mysql
log-slow-sql: true
slow-sql-millis: 2
slf4j:
data-source-log-enabled: true
data-source-logger-name: DRUID
statement-executable-sql-log-enable: true
statement-logger-name: DRUID
3.创建数据源枚举类
4.创建相关注解(可选)
5.编写aop切数据源
aop代码 @Component @Aspect @Order(-100) @Slf4j public class DataSourceSwitchAspect {
@Pointcut("execution(* com.dxh.multi.source.base.service..*.*(..))")private void dbBaseAspect() {}
@Pointcut("execution(* com.dxh.multi.source.erp.service..*.*(..))")
private void dbErpAspect() {}
@Pointcut("execution(* com.dxh.multi.source.order.service..*.*(..))")
private void dbOrderAspect() {}
@Pointcut("execution(* com.dxh.multi.source.finance.service..*.*(..))")
private void dbFinanceAspect() {}
@Pointcut("execution(* com.baomidou.mybatisplus.service..*.*(..)) ")
private void dbDefault() {}
@Before( "dbDefault()" )
public void dbDefault(JoinPoint joinPoint) {
String packageName = joinPoint.getThis().getClass().getPackage().getName();
switch (packageName) {
case "com.dxh.multi.source.base.service.impl":
dbBase(joinPoint);
break;
case "com.dxh.multi.source.erp.service.impl":
dbErp(joinPoint);
break;
case "com.dxh.multi.source.order.service.impl":
dbOrder(joinPoint);
break;
case "com.dxh.multi.source.finance.service.impl":
dbFinance(joinPoint);
break;
default:
dbBase(joinPoint);
}
log.debug("公共方法切换数据源");
}
@Before( "dbBaseAspect()" )
public void dbBase(JoinPoint joinPoint) {
log.debug("切换到base 数据源...");
setDataSource(joinPoint, DBTypeEnum.dbBase);
}
@Before("dbErpAspect()" )
public void dbErp (JoinPoint joinPoint) {
log.debug("切换到erp 数据源...");
setDataSource(joinPoint,DBTypeEnum.dbErp);
}
@Before("dbOrderAspect()" )
public void dbOrder (JoinPoint joinPoint) {
log.debug("切换到order 数据源...");
setDataSource(joinPoint,DBTypeEnum.dbOrder);
}
@Before("dbFinanceAspect()" )
public void dbFinance (JoinPoint joinPoint) {
log.debug("切换到finance 数据源...");
setDataSource(joinPoint,DBTypeEnum.dbFinance);
}
/**
* 添加注解方式,如果有注解优先注解,没有则按传过来的数据源配置
* @param joinPoint
* @param dbTypeEnum
*/
private void setDataSource(JoinPoint joinPoint, DBTypeEnum dbTypeEnum) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
DataSource dataSourceSwitch = methodSignature.getMethod().getAnnotation(DataSource.class);
if (Objects.isNull(dataSourceSwitch)) {
DbContextHolder.setDbType(dbTypeEnum);
}else{
log.debug("通过注解切换数据源,目标:"+dataSourceSwitch.value());
DbContextHolder.setDbType(dataSourceSwitch.value());
}
}
}
6.干掉喧闹的DataSourceAutoConfiguration,重写MybatisConfig 陈独秀同学请坐下,给我们的SqlSessionFactory一个机会
mybatis config 代码 @EnableConfigurationProperties({MybatisPlusProperties.class}) @AutoConfigureBefore({DataSourceAutoConfiguration.class}) @Configuration @MapperScan(basePackages = {"com.dxh.multi.source.**.mapper"}, markerInterface = MyMapper.class) public class MybatisPlusConfig {
@Autowiredprivate MybatisPlusProperties properties;
/**
* mybatis-plus分页插件<br>
* 文档:http://mp.baomidou.com<br>
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean(name = "db-base")
@ConfigurationProperties(prefix = "spring.datasource.druid.db-base")
public DataSource dbBase() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db-erp")
@ConfigurationProperties(prefix = "spring.datasource.druid.db-erp")
public DataSource dbErp() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db-order")
@ConfigurationProperties(prefix = "spring.datasource.druid.db-order")
public DataSource dbOrder() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db-finance")
@ConfigurationProperties(prefix = "spring.datasource.druid.db-finance")
public DataSource dbFinance() {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
*
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("db-base") DataSource dbBase,
@Qualifier("db-erp") DataSource dbErp,
@Qualifier("db-order") DataSource dbOrder,
@Qualifier("db-finance") DataSource dbFinance) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.dbBase.getValue(), dbBase);
targetDataSources.put(DBTypeEnum.dbErp.getValue(), dbErp);
targetDataSources.put(DBTypeEnum.dbOrder.getValue(), dbOrder);
targetDataSources.put(DBTypeEnum.dbFinance.getValue(), dbFinance);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(dbBase);
return dynamicDataSource;
}
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
sqlSessionFactory.setVfs(SpringBootVFS.class);
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
sqlSessionFactory.setPlugins(new Interceptor[]{
paginationInterceptor()
});
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
sqlSessionFactory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
sqlSessionFactory.setMapperLocations(this.properties.resolveMapperLocations());
}
sqlSessionFactory.setGlobalConfig(globalConfiguration());
return sqlSessionFactory.getObject();
}
@Bean
public GlobalConfiguration globalConfiguration() {
GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
conf.setLogicDeleteValue("-1");
conf.setLogicNotDeleteValue("1");
conf.setIdType(0);
conf.setDbColumnUnderline(true);
conf.setRefresh(true);
return conf;
}
} 7.填充各种crud代码及单元测试(配合代码生成器更佳 关于代码生成器&使用方式)
8.其他注意事项 1)数据源默认如下
2)@DataSource注解优先于以上默认配置 3)除了注解,可以使用 DbContextHolder.setDbType(DBTypeEnum.dbErp)切换数据源。
4)数据源切换后,事务回滚的——木有
以上是 使用SpringAbstractRoutingDataSource完成多数据源管理 的全部内容, 来源链接: utcz.com/z/510591.html