使用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 {

@Autowired

private 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

回到顶部