Spring+Mybatis项目中通过继承AbstractRoutingDataSource实现数据库热切换

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

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

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

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

再新增一个方法:refreshDataSources

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

        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        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的配置方法,只是多了一个数据源的配置

<bean id="dynamicDataSource" class="cn.jteee.sycerp.server.datasources.DynamicDataSource">    <property name="targetDataSources">        <map>            <entry value-ref="dataSource" key="sycerp_system"/>        </map>    </property>    <property name="defaultTargetDataSource" ref="dataSource"/></bean>

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

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

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

下面是DataSourceContextHolder的代码

public class DataSourceContextHolder {

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

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

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

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

}

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

时间: 2024-07-31 18:23:00

Spring+Mybatis项目中通过继承AbstractRoutingDataSource实现数据库热切换的相关文章

Spring Boot项目中使用jdbctemplate 操作MYSQL数据库

不废话,先来代码 pom文件: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

Spring Boot项目中如何定制PropertyEditors

本文首发于个人网站:Spring Boot项目中如何定制PropertyEditors 在Spring Boot: 定制HTTP消息转换器一文中我们学习了如何配置消息转换器用于HTTP请求和响应数据,实际上,在一次请求的完成过程中还发生了其他的转换,我们这次关注将参数转换成多种类型的对象,如:字符串转换成Date对象或字符串转换成Integer对象. 在编写控制器中的action方法时,Spring允许我们使用具体的数据类型定义函数签名,这是通过PropertyEditor实现的.Propert

Spring Boot项目中如何定制拦截器

本文首发于个人网站:Spring Boot项目中如何定制拦截器 Servlet 过滤器属于Servlet API,和Spring关系不大.除了使用过滤器包装web请求,Spring MVC还提供HandlerInterceptor(拦截器)工具.根据文档,HandlerInterceptor的功能跟过滤器类似,但拦截器提供更精细的控制能力:在request被响应之前.request被响应之后.视图渲染之前以及request全部结束之后.我们不能通过拦截器修改request内容,但是可以通过抛出异

在Spring Boot项目中使用Spock测试框架

摘自:https://www.cnblogs.com/javaadu/p/11748473.html 本文首发于个人网站:在Spring Boot项目中使用Spock测试框架 Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring Boot项目中使用该框架写优雅.高效以及DSL化的测试用例.Spock通过@RunWith注解与JUnit框架协同使用,另外,Spock也可以和Mockito(Spring Boot应用的测试——Mockito

项目记录:spring+springmvc 项目中 @Transactional 失效的解决方法

第一步,修改spring的配置文件和springmvc的配置文件 --------------------------------applicationContext.xml <context:annotation-config/>  <context:component-scan base-package="com.xxx"> <context:exclude-filter type="annotation" expression=&

控制反转和spring在项目中可以带来的好处

Spring实例化Bean的三种方式分别是: 1,xml配置使用bean的类构造器 <bean id="personService" class="cn.service.impl.PersonServiceBean"></bean> 2,xml配置+factory类,使用静态工厂方法实例化 <bean id="personService2" class="cn.service.impl.PersonServ

Spring Boot 项目中使用JSP

1    第2-2课:Spring Boot 项目中使用JSP JSP(Java Server Pages,Java 服务器页面)是一个简化的 Servlet 设计,它是由 Sun Microsystems 公司倡导.许多公司参与一起建立的一种动态网页技术标准.JSP 技术类似 ASP 技术,它是在传统的网页 HTML(标准通用标记语言的子集)文件(.html)中插入 Java 程序段(Scriptlet)和 JSP 标记(tag),从而形成 JSP 文件,后缀名为(*.jsp).用 JSP 开

SpringBoot Mybatis项目中的多数据源支持

1.概述 有时项目里里需要抽取不同系统中的数据源,需要访问不同的数据库,本文介绍在Springboot+Mybatis项目中如何支持多数据源操作. 有需要的同学可以下载 示例代码 2.建数据源 首先,我们建两个测试库 test1 test2,分别建两个表,分别添加一些测试数据 CREATE TABLE `groupidinfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `groupId` varchar(255) DEFAULT NULL, `versio

在Spring Boot项目中使用Redis集群

Redis安装 Mac 系统安装Redis brew方式安装 在命令汗执行命令 brew install redis 安装完成之后的提示信息 ==> Downloading https://homebrew.bintray.com/bottles/redis-5.0.2.mojave.bottle.tar.gz ######################################################################## 100.0% ==> Pouring