
项目要实现多数据源动态切换,咋搞?
在做项目的时候,几乎都会用到数据库,很多时候就只连一个数据库,但是有时候我们需要一个项目操作多个数据库,不同的业务功能产生的数据存到不同的数据库,那怎么来实现数据源的动态、灵活的切换呢?今天我们就来实现这个功能。
前期准备工作
我们需要有一台联网的电脑(用于maven自动下载依赖),并且电脑安装JDK 8、IDEA、MySQL数据库、maven,首先创建一个springboot项目(SSM也行)。springboot版本和SSM版本的代码都已经放到码云托管。感兴趣的可以去下载https://gitee.com/itwalking/springboot-dynamic-datasource,https://gitee.com/itwalking/ssm-dynamic-datasource
实现思路
首先讲一下我们的实现思路,平时我们做项目,都会用到spring
来集成我们的数据源,连接mysql
或Oracle
数据库,通过暴露出DataSource
相关的接口,然后不同的数据库都可以集成过来,我们只需要配置数据源的四大参数即可,这是我们往常的做法。而如果使用动态数据源的话,Spring
也为我们提供了相应的扩展点,那就是AbstractRoutingDataSource
抽象类,它同样是jdbc
的DataSource
接口的实现类。
代码
废话不多说,我们直接上代码。
创建我们自己的数据源DynamicDataSource
继承AbstractRoutingDataSource
,实现它的抽象方法determineCurrentLookupKey
,这个方法其实就是实现动态选择数据源的关键,通过这个方法返回的对象关联到我们的数据源。
DynamicDataSource
中有一个ThreadLocal
用来保存我们当前选择的数据源名称,代码中的注释写的很清楚了。其中ThreadLocal
的泛型是DataSourceName
,DataSourceName
是我们自己定义的一个枚举类,用于定义我们的数据源名称,我这里拿两个数据源做演示,并命名为FIRST
, SECOND
然后自定义一个注解,用于标注我们操作数据库时选择哪个数据源,很简单只有一个name属性,默认是 DataSourceName.FIRST
有了这些还不够,我们还需要根据我们的注解里的name属性动态的去修改 DynamicDataSource
中 ThreadLocal
中保存的数据库名称,每次执行SQL前都要修改数据源,这样才能达到修改数据源的目的。那很显然我们就需要spring AOP
来完成这个操作了。
如下,DynamicDataSourceAspect
是我们定义的一个切面类,同时也定了三个切点,分别去切方法上带@CurDataSource
注解的方法,类上带@CurDataSource
注解的类,以及按包名去切。这样,我们的动态数据源就支持方法级别的、类级别的、包级别的动态配置了。
仔细看一下这个切面类的环绕通知这个方法的逻辑,可以发现,我们首先看的是方法上的注解,然后再看类上的注解,最后看是否配置了包级别数据源。
基本上,该有的类我们都写完了,剩下就是验证。
验证之前我们还需要进行一些配置。
配置多数据源
这里,我们使用的是阿里的Druid数据源,用springboot自带的也行。我们可以看到在Druid:
配置下,原本直接就配置url、name这些参数,我们新增了一级分别是first和second,用于配置多个数据源
然后javaconfig配置类。
配置了三个bean,前两个是数据源的bean,使用@ConfigurationProperties
注解,让springboot帮我们去配置文件读取指定前缀的配置,这样我们刚才配的两个数据源参数就区分开了。
然后第三个bean是我们配置的叫做dataSource的bean,用于覆盖spring默认的DataSource
,在这个bean中,我们把所有的数据源注入进去,这里我们有两个,命名为FIRST和SECOND,以及我们要配置的包级别的数据源,然后调用构造函数创建DynamicDataSource
我们的动态数据源。并指明了默认的数据源。
然后就是我们的启动类了,我们需要禁用掉spring的自动配置数据源,和Druid的自动配置数据源,使用我们自定义的动态数据源。
操作Mybatis
我就不多说了,这里我在两个数据库(walking_mybatis和walking_mybatis2)里创建了相同的user表,我们测试的时候观察插入到哪个表就OK了。
项目整体结构
测试
我们在save_1
上添加注解指明使用SECOND,在save_2
则没有,UserService1
类上也没用注解,同样的,在配置类里也没配置UserService1
的包名,那么save_2
将会使用默认的数据源那就是FIRST
controller
运行,访问http://localhost:9966/walking/test01
日志输出
查看数据库则第二个数据库新增一条数据。
完整代码我已上传gitee码云,详细的测试都在这三个service包下和test包下,感兴趣的可以去下载代码看看。
实现动态数据源切换就是这么简单。下次我们看一下动态数据源的原理。
总结一下
1、继承AbstractRoutingDataSource实现多数据源及默认数据源的配置
2、注解+AOP,实现动态修改数据源的逻辑
3、排除spring和Druid(如果引入了第三方数据库连接池)默认的自动配置数据源
动手操作下一下,SQL和项目都已上传。
本文转载自公众号BiggerBoy
