Spring+Mybatis项目中通过继承AbstractRoutingDataSource实现数据库热切换
admin
2023-05-30 04:00:16
0次

  在做ERP项目的时候有个需求是能够管理和切换账套,一个账套就是一个数据库,那么就需要实现数据库的热切换。网上找了很多资料再结合项目的具体需求实现了一个还算比较好用的数据库热切换。

  原理是首先继承AbstractRoutingDataSource并实现determineCurrentLookupKey方法,方法的内容为

protected Object determineCurrentLookupKey() {
    return DataSourceContextHolder.getDataSourceType();
}

这个方法的功能是再执行sql之前spring会先执行这个方法,并从数据源Map中通过这个方法返回的key去确定要使用的数据源。

  再新增一个方法:refreshDataSources

private void refreshDataSources(List databaseList) {
    if (databaseList != null && databaseList.size() > 0) {
        BasicDataSource templateDataSource = (BasicDataSource) this.context.getBean("dataSource");//模板数据源

        Map targetDataSources = new HashMap();
        for (String database : databaseList) {
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(templateDataSource.getDriverClassName());
            dataSource.setUrl(regexReplaceUrl(templateDataSource.getUrl(), database));
            dataSource.setUsername(templateDataSource.getUsername());
            dataSource.setPassword(templateDataSource.getPassword());
            dataSource.setMaxActive(templateDataSource.getMaxActive());
            dataSource.setMaxIdle(templateDataSource.getMaxIdle());
            dataSource.setDefaultAutoCommit(templateDataSource.getDefaultAutoCommit());
            dataSource.setTimeBetweenEvictionRunsMillis(templateDataSource.getTimeBetweenEvictionRunsMillis());
            dataSource.setMinEvictableIdleTimeMillis(templateDataSource.getMinEvictableIdleTimeMillis());
            targetDataSources.put(database, dataSource);
        }
        targetDataSources.put("sycerp_system", templateDataSource); //加入默认dataSource

        this.setTargetDataSources(targetDataSources);
        this.setDefaultTargetDataSource(targetDataSources.get("sycerp_system"));
    }
    super.afterPropertiesSet();
}


// 这个方法的功能是将已经配置好的默认数据源的url中的database段替换会databaseList中的字符串
private String regexReplaceUrl(String url, String database) {
    return Pattern.compile("[/][a-z0-9_]+[\\?]").matcher(url).replaceAll("/" + database + "?");
}

这个方法的功能是将传入的databaseList(需要热切换的数据库名称列表),除了datasource的url需要替换外其他的属性都通过默认配置好的数据源中配置的属性,最后将封装好的数据源集合放入targetDataSources中,然后调用afterPropertiesSet方法刷新数据源,afterPropertiesSet的具体内容可以查看源码。

其中,这段代码中的context对象是通过实现ApplicationContextAware接口的setApplicationContext方法取得的,spring会自动注入applicationContext对象。

  然后就是配置,我们还是按照常规的spring整合mybatis的配置方法,只是多了一个数据源的配置

id="dynamicDataSource" class="cn.jteee.sycerp.server.datasources.DynamicDataSource">
   name="targetDataSources">
       
           value-ref="dataSource" key="sycerp_system"/>
       
   

   name="defaultTargetDataSource" ref="dataSource"/>

其中dynamicDataSource就是上面实现AbstractRoutingDataSource的类,里面ref的dataSource就是默认的数据源,其他配置数据ref的地方就使用这个dynamicDataSource,而不是dataSource。

  最后就是怎么使用。因为dynamicDataSource已经被spring管理起来了,所以,我们只需要在我们会用到的地方先生成一个数据库名称列表,可以从其他数据库中查询,然后调用refreshDataSources方法,最后调用

DataSourceContextHolder.setDataSourceType("你要切换的数据库名称");

下面是DataSourceContextHolder的代码

public class DataSourceContextHolder {

    private static final ThreadLocal contextHolder = new ThreadLocal();

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

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

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

}

  到此,一个完整的实现数据库热切换的功能就全部实现了,有其他特定的需求可以在此基础上修改。

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...