SpringBoot下多数据源的使用以及对事务注解的兼容。
多数据源配置
https://blog.csdn.net/qq_34697930/article/details/135508744
1. 多数据源配置
在实际开发中,经常可能遇到在一个应用中可能需要访问多个数据库的情况,微服务版本采用了dynamic-datasource
动态多数据源组件,使用参考:
1、对应模块pom
加入cloudsea-common-datasource
依赖
1 2 3 4
| <dependency> <groupId>com.cloudsea</groupId> <artifactId>cloudsea-common-datasource</artifactId> </dependency>
|
依赖于
1 2 3 4 5 6
| <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.2.1</version> </dependency>
|
2、配置主从数据库,在datasource下面加一个master(本来是不用的):
1 2 3 4 5 6 7
| spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://8.146.199.130:3306/otaru?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 username: root password: Why185999
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| spring: datasource: dynamic: datasource: master: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://8.146.199.130:3306/otaru?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 username: root password: Why185999
|
3、cloudsea-common-datasource
定义数据源注解,对应datasource
配置的不同数据源节点
项目默认了主Master
从Slave
注解可以直接使用,其他的可以根据项目实际情况去添加。
4、使用注解在需要切换数据源的方法上或类上。
1 2 3 4 5 6 7 8 9 10 11 12
| @Master public void insertA() { return xxxxMapper.insertXxxx(); }
@Slave public void insertB() { return xxxxMapper.insertXxxx(); }
|
2. @Transactionl注解
多种形式的事务使用:
https://blog.csdn.net/qq_52524736/article/details/138657889
3. RMS实际操作
3.1. Nacos配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| spring: datasource: dynamic: primary: master datasource: master: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.147.54:3306/rmsdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&noAccessToProcedureBodies=true username: root password: root slave: enabled: true username: postgres password: 123456 url: jdbc:postgresql://192.168.147.54:5432/rmsdb?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&allowMultiQueries=true¤tSchema=public driver-class-name: org.postgresql.Driver
|
3.2. 使用注解@DS
使用@DS(“slave”)注解切换数据源
@DS注解加到mapper接口、service接口、service方法里都不生效,应该添加到service实现类或者实现类里具体的方法上。
3.3. 使用注解@Slave
成功条件:
- 主方法上不加事务注解
- 小方法中新建事务注解,跳出事务注解(原因是默认的也会开启一个事务注解,我们也需要跳出)
1
| @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
|
- 在mapper的方法上添加@Slave注解
- 如果还是不行的话,试试在nacos配置文件中,设置primary库
3.4. @DSTransactional注解
https://www.5axxw.com/questions/simple/kbbuz9
https://www.cnblogs.com/zhaobo1997/p/17976348
如果方法内部需要切换数据源,直接将最外层的注解@Transactional切换为@DSTransactional
3.5. 手动切换数据源
https://blog.csdn.net/u012383839/article/details/136919569
1 2 3 4 5 6 7 8
| try { DynamicDataSourceContextHolder.push("slave"); pgReturnObj = resSpecMapper.selectPGGeom(pgParamObj); } catch (Exception e) { log.info("pg库数据源切换失败:" + e.getMessage()); }finally { DynamicDataSourceContextHolder.clear(); }
|
3.6. 手动切换数据源并查看数据源名称
这种查询的方法只能看到这种手动push的数据源的名称
1 2 3 4 5 6 7
| @GetMapping("/dataSourceName") public void dataSourceName() { DynamicDataSourceContextHolder.push("master"); log.info("dataSourceName1:{}", DynamicDataSourceContextHolder.peek()); DynamicDataSourceContextHolder.clear(); log.info("dataSourceName2:{}", DynamicDataSourceContextHolder.peek()); }
|
3.7. 事务与矛盾
https://www.cnblogs.com/sun-10387834/p/16528339.html
想要无伤通关有两种情况:
- 取消主方法中上的
@Transactional
注解
- 如果主方法名字是insert或者create等名字,可能会默认实现了事务,那么我建议将多数据源操作放在一个方法中。然后在这个方法上添加新事务注解:
1
| @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
4. 解决方案
4.1. 外事务+mapper-slave注解
https://blog.csdn.net/csdn570566705/article/details/132738498
Service主方法:
1 2 3 4
| @DSTransactional public void main(){ addStationGeom(); }
|
Service内部方法无操作:
1 2 3 4 5 6
| public int addStationGeom(SpcStation spcStation) {
spcStationMapper.addStationGeom(paramObj);
return 1; }
|
Mapper方法:
1 2
| @Slave void addStationGeom(JSONObject paramObj);
|
亲测事务有效,在整个方法的数据库方法结束之前,不会有sql操作?那会不会影响回查?
实际上不影响回查,虽然在表里看不见,但是不影响我们的查询操作。