在Spring Boot中,可以通过多种方式实现多数据源的动态切换效果,本篇介绍第一种实现方案。
一 AbstractRoutingDataSource
Spring Boot
提供了org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
这个类,其中#determineCurrentLookupKey
方法可以让用户根据自己定义的规则在某一个SQL执行之前动态地选择想要的数据源。
|
因此,我们的整体实现逻辑就很清晰了,具体分为以下几个步骤:
- 定义
DynamicRoutingDataSource
类,继承AbstractRoutingDataSource
类并实现#determineCurrentLookupKey
方法(具体逻辑是从当前线程的ThreadLocal
中获取我们在某一个SQL执行之前通过AOP切面动态指定的数据源名称); - 在
application.yml
中配置多个数据源; - 解析在
application.yml
中配置的多个数据源,然后生成DynamicRoutingDataSource
实例,并设置默认数据源(defaultTargetDataSource
)和其他数据源(targetDataSources
); - 调用
AbstractRoutingDataSource
的#getConnection
的方法的时候,会先调用#determineTargetDataSource
方法获取具体的数据源,而在这个方法中会进一步调用我们在DynamicRoutingDataSource
类中自定义的#determineCurrentLookupKey
方法,最后在返回DataSource
后再进行#getConnection
的调用。显然,剩下就是具体的SQL逻辑执行了。
二 具体实现
(1)测试使用的数据库
这里我们创建3个数据库,分别是:db01
、db02
、db03
,然后这3个数据库都有一张名为user_info
的表,表结构一样,只是数据不同。
|
(2)动态切换数据源的上下文
|
(3)定义DynamicRoutingDataSource
类
主要是继承AbstractRoutingDataSource
类并实现#determineCurrentLookupKey
方法,其具体逻辑是从当前线程的ThreadLocal
中获取我们在某一个SQL执行之前通过AOP切面动态指定的数据源名称。
|
(4)新增application-datasource.yml
配置文件
新建这个用于测试的配置文件,主要配置了接下来需要用到的多个数据源,其关键配置如下:
|
(5)解析在application-datasource.yml
中配置的多个数据源
|
(6)通过AOP+注解
实现数据源的动态切换
i)在pom.xml
文件中添加切面需要的依赖:
|
ii)新增一个用于切换数据源的注解:
|
iii)定义一个AOP的通知类:
|
iv)定义一个Advisor
,将通知注入到指定的切点:
|
v)导入上面的数据源配置,以及启动切面:
|
三 效果测试
(1)新建两个测试使用的Mapper
UserInfoMapper
为插件自动生成,没有添加我们自定义的@DataSource
注解,用于测试不添加注解的情况下默认使用的数据源。
|
UserInfoDynamicMapper
为手动新建的几个方法,用于测试数据源的动态切换效果。
|
其对应的UserInfoDynamicMapper.xml
文件是:
|
(2)使用单元测试测试「动态切换数据源」的效果
|
注:以上测试代码基于Junit5 测试框架编写,需要的依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
运行单元测试后,测试效果如下:
可以发现,除了最后手动抛出一个异常的方法,其他几个方法都测试通过了。然后,通过查询数据库中的数据还可以发现,事务做了我们预期效果的回滚,因此本篇文章介绍的「多数据源动态切换」方案是可行的。