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();
    }

}

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

相关内容

热门资讯

我国首座抗17级台风高技术难度... 本文转自【新华网】; 新华社北京8月6日电(记者王悦阳、梁姊)中国海油8月6日宣布,我国自主设计建造...
山西省灵丘县科技馆里“热度”飙... 央广网大同8月6日消息(记者张洁 通讯员马明清)8月5日,山西省大同市灵丘县科技馆展厅内人头攒动、氛...
校地协同 聚力科研攻关 8月3日,在市沙漠综合治理中心主任张雁平的陪同下,青岛农业大学教授刘建龙、内蒙古自治区林科院研究员杨...
唐波、崔洪芝获颁2025年度山... 8月6日下午,全省科技大会在济南召开。会上,宣读《中共山东省委山东省人民政府关于2025年度山东省科...
台风“白海豚”逐渐逼近华东沿海... 据中央气象台消息,今年第13号台风“白海豚”的中心8月6日14时位于距离浙江省温州市偏东方向约120...
阿联酋、土耳其、沙特等8国外长... 【环球网报道 记者 索炎琦】据《以色列时报》等媒体报道,阿联酋、卡塔尔、约旦、印度尼西亚、巴基斯坦、...
字节CEO梁汝波承认大语言模型... 8月6日,字节跳动召开2026年度年中全员会,公司CEO梁汝波、新成立的“创造力服务平台”(Crea...
知名经济学家、教育家、出版人高... 澎湃新闻记者 蒋子文 岳怀让据台湾《远见》杂志网站消息,知名经济学家、教育家、出版人,远见‧天下文化...
“女生洗澡,大叔帮搓背”,苏泊... 国民级厨房小家电品牌苏泊尔,最近因几段AI生成的短视频,被指内容低俗,引发关注。而就在不久前,苏泊尔...
网红,被罚10万欧元? 在法国,一个中等收入消费者,打开手机上的跨境电商平台,花几欧元就能买到一件不错的T恤,而同样的产品在...