前言
在现在开发的过程中应该大多数朋友都有遇到过切换数据源的需求。比如现在常用的数据库读写分离,或者就是有两个数据库的情况,这些都需要用到切换数据源。
手动切换数据源
使用Spring
的AbstractRoutingDataSource
类来进行拓展多数据源。
该类就相当于一个dataSource
的路由,用于根据key
值来进行切换对应的dataSource
。
下面简单来看下AbstractRoutingDataSource
类的几段关键源码:
|
|
可以看到其中获取链接的方法getConnection()
调用的determineTargetDataSource
则是关键方法。该方法用于返回我们使用的数据源。
其中呢又是determineCurrentLookupKey()
方法来返回当前数据源的key
值。
之后通过该key值在resolvedDataSources
这个map中找到对应的value
(该value就是数据源)。
resolvedDataSources
这个map则是在:
|
|
这个方法通过targetDataSources
这个map来进行赋值的。targetDataSources
则是我们在配置文件中进行赋值的,下面会讲到。
再来看看determineCurrentLookupKey()
方法,从protected
来修饰就可以看出是需要我们来进行重写的。
DynamicDataSource 和 DataSourceHolder
于是我新增了DynamicDataSource
类,代码如下:
|
|
代码很简单,继承了AbstractRoutingDataSource
类并重写了其中的determineCurrentLookupKey()
方法。
这里直接用DataSourceHolder
返回了一个数据源。
DataSourceHolder
代码如下:
|
|
这里我使用了ThreadLocal
来保存了数据源,关于ThreadLocal
的知识点可以查看以下这篇文章:
解密ThreadLocal
之后在Spring
的配置文件中配置我们的数据源,就是上文讲到的为targetDataSources赋值
:
|
|
这里分别配置了两个数据源:ssm1DataSource
和ssm2DataSource
。
之后再通过Spring
的依赖注入方式将两个数据源设置进targetDataSources
。
接下来的用法相比大家也应该猜到了。
就是在每次调用数据库之前我们都要先通过
DataSourceHolder
来设置当前的数据源。看下demo:
123456 public void selectByPrimaryKey() throws Exception {DataSourceHolder.setDataSources(Constants.DATASOURCE_TWO);Datasource datasource = dataSourceService.selectByPrimaryKey( 7);System.out.println(JSON.toJSONString(datasource));}
详见我的单测。
使用起来也是非常简单。但是不知道大家注意到没有,这样的做法槽点很多:
- 每次使用需要手动切换,总有一些人会忘记写(比如我)。
- 如果是后期需求变了,查询其他的表了还得一个个改回来。
那有没有什么方法可以自动的帮我们切换呢?
肯定是有的,大家应该也想得到。就是利用Spring
的AOP
了。
自动切换数据源
首先要定义好我们的切面类DataSourceExchange
:
|
|
逻辑也比较简单,就是在执行数据库操作之前做一个切面。
- 通过
JoinPoint
对象获取目标对象。 - 在目标对象中获取包名来区分不同的数据源。
- 根据不同数据源来进行赋值。
- 执行完毕之后将数据源清空。
关于一些JoinPoint
的API:
|
|
将两个不同的数据源的实现类放到不同的包中,这样今后如果还需要新增其他数据源也可以灵活的切换。
看下Spring
的配置:
|
|
这是在我们上一篇整合redis缓存的基础上进行修改的。
这样缓存和多数据源都满足了。
实际使用:
|
|
这样看起来就和使用一个数据源这样简单,再也不用关心切换的问题了。
总结
不过按照这样的写法是无法做到在一个事务里控制两个数据源的。这个我还在学习中,有相关经验的大牛不妨指点一下。