基于AbstractRoutingDataSource的动态切换数据库

当项目发展到一定阶段,就需要对数据库进行一定的优化。一般会对数据库进行横向和纵向切库分表,但是这样的问题就来了,在我们操作数据库时,需要根据切分规则提前获得我们需要的数据库的连接,这明显会加重程序员的负担。

比如我们将“用户信息数据库”按照用户注册的年月来分库,在用户注册的时候,为用户分配一个以yyyyMM开头的唯一标示,以方便我们能快速定位到切分后的子数据库。那么问题来了,我们在项目中,如何动态且方便的获得我们需要的数据源呢?Spring提供了一个解决方案,那就是基于AbstractRoutingDataSource的动态数据源切换。

AbstractRoutingDataSource的类结构:

想要使用,只需要重写determineCurrentLookupKey方法,在说明他的作用之前,先看下调用他的位置:

private Map

    protected DataSource determineTargetDataSource() {
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
        Object lookupKey = determineCurrentLookupKey();
        DataSource dataSource = this.resolvedDataSources.get(lookupKey);
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
            dataSource = this.resolvedDefaultDataSource;
        }
        if (dataSource == null) {
            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
        }
        return dataSource;
    }

可以看到,determineCurrentLookupKey的返回值会作为Map的key来查找数据库连接。而determineTargetDataSource方法通常是用来返回给调用端DataSource,因此我们可以通过重写这两个方法,来实现动态切换数据库。

首先定义一个Bean来保存数据库信息,也将它作为Map的key,数据库连接作为Value。

public class DatabaseDefineBean {
    private String userName;
    private String passWord;
    private String url;

    ...getter/setter
}

编写我们自己的数据源

public class MyDataSource extends AbstractRoutingDataSource {
    private String driverClassName;
    static ThreadLocal<DatabaseDefineBean> defineBeans = new ThreadLocal<DatabaseDefineBean>();

    @Override
    protected Object determineCurrentLookupKey() {
        return defineBeans.get();
    }

    @Override
    protected DataSource determineTargetDataSource() {
        DriverManagerDataSource dataSource = getDataSource((DatabaseDefineBean) determineCurrentLookupKey());
        return dataSource;
    }

    private DriverManagerDataSource getDataSource(DatabaseDefineBean databse) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource(databse.getUrl(), databse.getUserName(),
                databse.getPassWord());

        return dataSource;
    }
}

这里使用Spring+Mybatis测试(源码及数据库文件下载):

    String userName = "writeuser";
    String passWord = "writeuser";
    String url = "jdbc:mysql://192.168.1.61:3306/DataBaseRoute";

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"/com/smart/config/spring-jdbc.xml"});
        MyDataSource.setDefineBeans(new DatabaseDefineBean(userName, passWord, url));
        DataSource dataSource = context.getBean(DataSource.class);

        System.out.println(dataSource);

        SqlSessionTemplate sessionTemplate =  context.getBean(SqlSessionTemplate.class);        

        DatabaseInfoMapper mapper = sessionTemplate.getSqlSessionFactory().openSession().getMapper(DatabaseInfoMapper.class);
        List<?> list = mapper.selectAll();
        System.out.println(list);
    }

那么如何动态切换呢?这里使用到了ThreadLocal,用于为每个线程保存一个副本,我们只需在操作数据库之前设置一下Database的基本信息就可以轻松获得想要的数据源了。

MyDataSource.setDefineBeans(new DatabaseDefineBean(userName, passWord, url));

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-29 01:00:16

基于AbstractRoutingDataSource的动态切换数据库的相关文章

Mybatis 动态切换数据库

mybatis介绍: 每一个Mybatis的应用程序都以一个SqlSessionFactory对象的实例为核心.SqlSessionFactory对象实例可以通过SqlSessionFactoryBuilder对象获得.SqlSessionFactoryBuilder对象可以从XML配置文件或从Configuration类的习惯准备的实例中构建SqlSessionFactory对象. 从XML文件中构建SqlSessionFactory的实例非常简单.这里建议使用类的路径的资源文件来配置,这样我

动态切换数据库源码解析

动态切库可用于SaaS环境,多租户环境 所以浏览器的每次请求都有可能是不同租户,需要动态切换数据库来支持业务场景. 又所以每次请求都需要识别是哪个租户,这里我们用到了ThreadLocal,以此来保存线程的本地变量,携带上租户的一些信息.而租户的信息可以从Session或Token中获取,或者是url路径参数 准备好以上条件信息 我们开始秀吧 创建 DruidDynamicDataSource 继承自 AbstractRoutingDataSource org.springframework.j

动态切换数据库(EF框架)

         文章简略:本文测试项目为Silverlight+EF+RIA Service动态切换数据库的问题 通常,Ado.net EntityFramework的数据库连接字符串ConnectionString是存在实体框架所在的类库项目中的配置文件中(.config)的,类似这样: <connectionStrings> <add name="{EFName}Entities" connectionString="metadata=res://*/

springAOP实现基于注解的数据源动态切换

需求 代码实现读写数据库分离 武器 spring3.0以上版本 实现思路 1.继承org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,自定义数据源路由. 2.实现数据源类型管理工具,诸如DBContextHolder,包含设置和读取当前数据源配置. 3.实现数据源切换的AOP. 4.自定义只读注解,诸如@ReadOnlyKey. 5.配置transactionManager,实现aop. 代码示例 1.自定义的

java 动态操作数据库

问题描述:比如项目现在要使用在南京的8的区,这时这8个区分别建了一个数据库,但是只有一个项目,每个区的用户都使用这个项目进行登录 问题难点:如何验证登录人属于哪个区,然后确认之后,如何进行数据库的切换: 问题思路:除了8个数据库之外,在建一个数据库:数据库中包含的几张表:储存登录用户的信息等,直接上图理解 一.数据库的建立 h_right : h_role:红色表示登录人  所属哪一区 h_role_right:  分配显示的菜单 h_role_sysuser:用于分配区编号 h_sysuser

EntityFramework For Mysql 动态切换数据源

1.简介 在工作中遇到一个问题.项目有三个数据库(三个数据库表结构一样),用户可以选择使用哪个数据库.其实就是动态切换数据库连接. 2.EntityFramework For Mysql 先来简单的介绍下mysql使用EntityFramework来操作数据库. 直接上代码: (1).先建个项目,安装mysql,entityframework相关包 (2).建立实体和对应的数据库表 (3).编写数据库连接字符串,编写context实体 这样就可以来使用Entityframework来访问mysq

基于Struts2 Spring ibatis Oracle10g架构 多数据源动态切换实例

一.概述 基于Spring动态配置多数据源,在大型的应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效的提高系统的水平伸缩性,而这样的解决方案就会补同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求以及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据. Spring配置多个数据源的方式和具体使用过程,Spring对于多数据源,以数据库表为参照,大体上可以分为两大类情况: 1.表级上的跨数据库,即对于不同的数据库却有不相同的表(表名和表结构完全

基于spring的aop实现多数据源动态切换

https://lanjingling.github.io/2016/02/15/spring-aop-dynamicdatasource/ 基于spring的aop实现多数据源动态切换 发表于 2016-02-15   |   分类于 spring  | 一.多数据源动态切换原理 项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此:又例如:读写分离数据库配置的系统. 1.多数据源设置: 1)静态数据源切换:一般情况下,我们可以配置多个数据源,然后为每个数据源写一套对应的

切换数据库+ThreadLocal+AbstractRoutingDataSource

最近项目用的数据库要整合成一个,所以把多源数据库切换的写法要清除掉.所以以下记载了多远数据库切换的用法及个人对源码的理解. 框架:Spring+mybatis+vertx,(多源数据库切换的用法不涉及vertx,所以,适用于ssh,sm,ssh...). 数据库:mysql 两个关键的api: 一:ThreadLocal, 二:AbstractRoutingDataSource. 我一直坚持先先学会使用,在去探究源码和原理. 部分一(实现代码): 以下为实现代码: DatabaseSource.