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








