前言:
这个项目是一个单体项目,并没有涉及到分布式事务,需求也比较直接,就是在一个请求方法里面,同时查询两个数据库的数据,并且往两个数据库插入数据的时候,要保证事务的一致性
1.多数据源依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.3.5</version> </dependency>
2.配置文件
server: port: 8080 spring: datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: master: url: xxx username: xxx password: xxx driver-class-name: com.mysql.cj.jdbc.Driver druid: pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 validation-query: SELECT 1 FROM DUAL test-on-borrow: false test-on-return: false test-while-idle: true time-between-eviction-runs-millis: 60000000 filters: stat,wall slave_1: url: xxx username: xxx password: xxx driver-class-name: com.mysql.cj.jdbc.Driver druid: pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 validation-query: SELECT 1 FROM DUAL test-on-borrow: false test-on-return: false test-while-idle: true time-between-eviction-runs-millis: 60000000 filters: stat,wall
注意:配置文件中的 master 是主要的数据源,slave_1 是从数据源(说是从数据源而已,实际上我这个项目并没有主从复制,读写分离这些,实际上就是另外的一个数据源)
3.项目结构:
nk_jewel_applet 数据库 用的是 数master 的据源:Test1Model 对应 nk_jewel_applet里 里面的 test1 表而 nk_product_pro 数据库 用的是 slave_1 的数据源:Test2Model 对应 nk_product_pro 里面的 test2 表
对应关系:
master ------> nk_jewel_applet ------> Test1Modelslave_1 ------> nk_product_pro ------> Test2Model
4.@DS注解(重点)
@DS 注解是用于切换数据源的,可用于指定的类用的是那一个数据源,可用于mapper接口的类上,也可以用于service的实现类上,也可以用于service的实现类的方法上,如下图:
- 用于mapp接口:
- 用于service的实现类:
- 用于service的实现类中的方法:
这个往下看,会讲解到的
注意:@DS的本质就是通过aop去实现的
5.测试
先把 @DS("slave_1") 注解写到 Test2Mapper 以及 Test2ServiceImpl 的类上先(表示这两个类中的所有请求数据库的操作,都会被切换成 'slave_1' 数据源中的数据库 ),例如:
- 表中的数据:
-
在同一个请求中,获取到两个表的数据
对应的service:
发请求:
可以看到已经成功了各自的数据
-
在同一个请求中,对两个数据库同时插入数据,并查询出来:
对应的service:
请求:
-
保证多数据原的事务一致性(@DSTransactional注解)
还是上面的添加例子,只要加入 @DSTransactional 注解,即可保证事务的一致性
修改了以下代码:
执行代码:可以看到报错了,然后去看下数据库,test1 表是否有添加数据
test1 表并没有插入数据,说明多数据事务已经成功