码迷,mamicode.com
首页 > 数据库 > 详细

基于AbstractRoutingDataSource的动态切换数据库

时间:2015-08-09 15:37:29      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:数据库   spring   

当项目发展到一定阶段,就需要对数据库进行一定的优化。一般会对数据库进行横向和纵向切库分表,但是这样的问题就来了,在我们操作数据库时,需要根据切分规则提前获得我们需要的数据库的连接,这明显会加重程序员的负担。
比如我们将“用户信息数据库”按照用户注册的年月来分库,在用户注册的时候,为用户分配一个以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));

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

基于AbstractRoutingDataSource的动态切换数据库

标签:数据库   spring   

原文地址:http://blog.csdn.net/u013769320/article/details/47376343

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!