springboot动态切换数据源

码云:switch-datasource-spring-boot-starter: 自定义starter,使用注解实现动态切换数据源

一,原理

我们知道mybatis的一般执行流程主要为:

加载配置文件 ----> 创建SqlSessionFactory -----> 获取sqlsession ----->调用mapper方法执行sql。

其中读取数据源创建DataSource是在SqlSessionFactory之前创建的,后面一系列流程是固定的,所有我们想动态切换数据源,只需将数据源切换为我们想要的就能实现动态切换。

这是就需要一个类保存数据源信息供sqlSessionFactory供其读取,而spring集成Mybatis的时候,就专门提供了一个这样的类,AbstractRoutingDataSource。

我们下看下AbstractRoutingDataSource这个类的几个重要属性:

 

targetDataSources:保存了所有数据源的信息,key 是数据源的标识符,value 是对应的 DataSource 对象。
defaultTargetDataSource:默认的当前数据源,如果无法根据当前的 key 值找到对应的数据源,则使用该默认数据源。
resolvedDataSources:解析好的数据源信息,可以根据key数据源标识取得解析好的DataSource。
因为AbstractRoutingDataSource为抽象类,继承的话需要实现一个接口determineCurrentLookupKey

根据AbstractRoutingDataSource的源码,可以发现当前使用的数据源是根据determineCurrentLookupKey这个方法的返回值去从resolvedDataSources解析好的数据源map集合中取的,所有我们就可以继承AbstractRoutingDataSource这个类,实现determineCurrentLookupKey方法,将返回值设置为我们想要切换的数据源名称,那么mybatis就是根据这个数据源构建sqlSessionFactory,那么后续执行都是基于这个数据源的,从而就是先了动态切换。

还有一点,每个线程使用的数据源可能不同,所以我们可以使用ThreadLocal存放数据源名称,从而保证线程安全。

二,设计分析

1,定义properties读取配置文件

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
    /**
     * 数据源信息
     */
    private Map<String, Map<String,String>> db;

    public Map<String, Map<String, String>> getDb() {
        return db;
    }

    public void setDb(Map<String, Map<String, String>> db) {
        this.db = db;
    }
}

:配置类这样定义,配置文件也要按照这个写,如

 

2,创建DataSourceContextHolder保存当前线程数据源名称

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceKey(String dataSourceKey){
        contextHolder.set(dataSourceKey);
    }

    public static String getDataSourceKey(){
        return contextHolder.get();
    }

    public static void clearDataSourceKey(){
        contextHolder.remove();
    }
}

3,创建DynamicDataSource继承AbstractRoutingDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }
}

4,定义配置类,将DynamicDataSource注册到spring

@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceConfig {

    @Resource
    private DataSourceProperties dataSourceProperties;

    @Bean
    public DataSource dataSource(){
        // 创建数据源
        Map<Object, Object> targetDataSources = new HashMap<>();

        Map<String, Map<String, String>> db = dataSourceProperties.getDb();
        for (String dbInfo : db.keySet()) {
            Map<String, String> objMap = db.get(dbInfo);
            targetDataSources.put(dbInfo,new DriverManagerDataSource(objMap.get("url"),objMap.get("username"),objMap.get("password")));
        }

        // 设置数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(targetDataSources.get("master"));
        return dynamicDataSource;
    }
}

5,测试

基于以上配置,就能实现动态数据源切换。

 使用

DataSourceContextHolder.setDataSourceKey("数据源名称");

就能实现动态切库,使用完成后可以使用

DataSourceContextHolder.clearDataSourceKey();

就会自动换成默认的主库,master

三,具体代码

本测试代码,是使用注解实现动态切换,比上面的多了自定义注解,starter和aop的使用。

giteeswitch-datasource-spring-boot-starter: 自定义starter,使用注解实现动态切换数据源

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隔山看水

你的鼓励与打赏是我创作的最大动

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值