springboot多数据源之AbstractRoutingDataSource

springboot继承AbstractRoutingDataSource可以实现数据源。

1.先写继承AbstractRoutingDataSource的类

(1).DynamicDataSource 是设置默认数据源和已经存在的所有数据源

(2).这个determineCurrentLookupKey是从当前线程获取设置的数据源

public class DynamicDataSource extends AbstractRoutingDataSource
{
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
    {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey()
    {
        return DynamicDataSourceContextHolder.getDateSoureType();
    }
}

2.DynamicDataSourceContextHolder设置当前线程处理数据源的类

public class DynamicDataSourceContextHolder {

    public static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    private static final ThreadLocal<String> DATASOURCE_CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源
     */
    public static void setDateSoureType(String dateSoureType) {
        logger.info("设置数据源={}", dateSoureType);
        DATASOURCE_CONTEXT_HOLDER.set(dateSoureType);
    }

    /**
     * 获得数据源
     */
    public static String getDateSoureType() {
        return DATASOURCE_CONTEXT_HOLDER.get();
    }

    /**
     * 清空数据源
     */
    public static void clearDateSoureType() {
        DATASOURCE_CONTEXT_HOLDER.remove();
    }
}

3.配置Hikari数据源和包位置

@Configuration
@MapperScan("com.fast.framework.dao")
public class HikariCustomConfig {

    public static final Logger logger = LoggerFactory.getLogger(HikariCustomConfig.class);

    @Value("${mybatis.config-location}")
    private String configLocation;
    @Value("${mybatis.type-aliases-package}")
    private String typeAliasespackage;

    @Bean("master")
    @ConfigurationProperties(prefix = "spring.datasource.hikari.master")
    public HikariDataSource masterDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean("second")
    @ConfigurationProperties(prefix = "spring.datasource.hikari.second")
    public HikariDataSource slaveDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dataSource(@Qualifier("master") DataSource masterDataSource, @Qualifier("second") DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(AllDatasource.MASTER.name(), masterDataSource);
        targetDataSources.put(AllDatasource.SECOND.name(), slaveDataSource);
        return new DynamicDataSource(masterDataSource, targetDataSources);
    }

    /**
     * @description: 配置mybatis的mapper和dao的位置
     */
    @Bean("sqlSessionFactoryBean")
    public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource);
        sqlSessionFactoryBean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources(configLocation));
        sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasespackage);
        return sqlSessionFactoryBean;
    }

    /**
     * 事务管理
     */
    @Bean
    public PlatformTransactionManager transactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

}

4.设置aop注解,通过注解设置数据源

@Aspect
@Order(1)
@Component
public class DataSourceAop {

    @Value("${spring.datasource.hikari.master.default-package}")
    private String masterPackage;
    @Value("${spring.datasource.hikari.second.default-package}")
    private String secondPackage;

    public static final Logger logger = LoggerFactory.getLogger(DataSourceAop.class);

    @Pointcut("execution(* com.fast.framework.dao..*.*(..))  ||@annotation(com.fast.common.annotation.ChooseDataSource)")
    public void switchDataSource() {
    }

    @Before("switchDataSource()")
    public void doBefore(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        ChooseDataSource chooseDataSource = method.getAnnotation(ChooseDataSource.class);//获取方法上的注解
        if (chooseDataSource == null) {
            chooseDataSource = joinPoint.getTarget().getClass().getAnnotation(ChooseDataSource.class);//获取类上面的注解
            if (chooseDataSource == null) {
                String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
                if (declaringTypeName.startsWith(masterPackage)) {
                    DynamicDataSourceContextHolder.setDateSoureType(AllDatasource.MASTER.name());
                    logger.info("使用包默认数据源,包={},数据源={}", masterPackage, AllDatasource.MASTER.name());
                } else if (declaringTypeName.startsWith(secondPackage)) {
                    DynamicDataSourceContextHolder.setDateSoureType(AllDatasource.SECOND.name());
                    logger.info("使用包默认数据源,包={},数据源={}", secondPackage, AllDatasource.SECOND.name());
                }
                return;
            } else {
                logger.info("类注解生效,切换数据源={}", chooseDataSource.dataSource().name());
            }
        } else {
            logger.info("方法注解生效,切换数据源={}", chooseDataSource.dataSource().name());
        }
        //获取注解上的数据源的值的信息
        String dataSourceName = chooseDataSource.dataSource().name();
        if (dataSourceName != null) {
            //给当前的执行SQL的操作设置特殊的数据源的信息
            DynamicDataSourceContextHolder.setDateSoureType(dataSourceName);
        }
        String nowDatasource = "".equals(dataSourceName) ? "默认数据源master" : dataSourceName;
        logger.info("AOP注解切换数据源,className" + joinPoint.getTarget().getClass().getName() + "methodName" + method.getName() + ";dataSourceName:" + nowDatasource);
    }

    @After("switchDataSource()")
    public void after(JoinPoint point) {
        //清理掉当前设置的数据源,让默认的数据源不受影响
        DynamicDataSourceContextHolder.clearDateSoureType();
    }
}

5.配置数据源和包位置

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      driver-class-name: com.mysql.cj.jdbc.Driver
      maximum-pool-size: 20
      max-lifetime: 30000
      idle-timeout: 30000
      master:
        default-package: com.fast.framework.dao.master
        jdbc-url: jdbc:mysql://localhost:3306/fastblack?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=true
        username: root
        password: 123456
      second:
        default-package: com.fast.framework.dao.second
        jdbc-url: jdbc:mysql://localhost:3306/base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=true
        username: root
        password: 123456

mybatis:
  config-location: classpath*:/mapper/*/*.xml
  type-aliases-package: com.fast.framework.model

6.枚举和切换数据源注解

public enum AllDatasource {
     MASTER,
     SECOND;
}

注解:

/**
 * @Auther: Administrator
 * @Date: 2019/6/9 16:36
 * @Description:设置数据源 优先级:1.方法注解 2.类注解 3.根据包路径设置的数据源
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChooseDataSource {

    AllDatasource dataSource() default AllDatasource.MASTER;
}

最后,这个是经过测试可以使用的,各位需要有基础,配置的时候直接拷贝修改一下就好了。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值