最近项目需求,需要用到多数据源配置,经过一番学习完成需求功能开发,本文介绍一下我用到的dynamic做动态数据源配置。
1. 依赖导入
这里用到dynamic依赖,和对应的数据源(mysql,oracle等)依赖。以下是dynamic依赖:
<dependency> <groupid>com.baomidou</groupid> <artifactid>dynamic-datasource-spring-boot-starter</artifactid> <version>3.5.0</version> </dependency>
2.yml配置
yml配置主要是将多个数据源分别配置,并指定默认数据源,具体yml配置参考如下:
spring:
datasource:
dynamic:
primary: kingbase # 设置主库为kingbase
strict: false # 严格匹配数据源,默认false,当为true时,未匹配到指定数据源时抛异常,false未匹配到指定数据源会使用默认数据源
datasource:
kingbase: # 这的kingbase是自定义的数据源名称,不是指数据库的类型
url: jdbc:kingbase8://${database_host:127.0.0.1}:${database_port:54323}/${database_dbname:kingbase}?servertimezone=gtm%2b8
username: ${database_username:system}
password: ${database_password:12345}
driverclassname: com.kingbase8.driver
type: com.alibaba.druid.pool.druiddatasource
mysql:
url: jdbc:mysql://${database_host:127.0.0.1}:${database_port:3306}/${database_dbname:mysql}?servertimezone=gmt%2b8&useunicode=true&characterencoding=utf8&usessl=false
username: ${database_username:root}
password: ${database_password:1234}
driverclassname: com.mysql.cj.jdbc.driver
type: com.alibaba.druid.pool.druiddatasource
使用时,只需要在对应的mapper上,使用注解@ds(“mysql”),指定当前mapper数据源为mysql数据源
3.多数据源失效问题
常见的多数据源失效问题可以从配置方面去排查,例如,yml配置,ds指定数据源配置等方面。
这里我介绍一下我在使用过程中遇到的多数据源失效问题。
问题情境
我在同一个方法中,先调用了主数据源(kingbase)中的某个表数据,然后再调用了从数据源(mysql)中的数据,然后执行下面业务逻辑,我这后面涉及到对数据库的写操作,我在方法上用了@transactional注解管理事务,然后我发现,调用主数据源的时候,数据获取正常,调用从数据源的时候,报错没有xx表,查看报错信息为kingbasesqlexception,就知道了调用的主数据源数据,多数据源失效了。于是开始排查
问题排查
(1) 配置问题
首先查看是否是配置原因,检查yml配置和mapper配置是否正确,然后我写了个测试接口,测试多数据源是否有效,测试接口直接调用获取从数据源数据,获取正确,不是这个原因。
(2)方法代理问题
我将获取数据的代码单独封装方法,然后通过自动注入service,用注入的service调用方法获取对应所需的数据,仍然发现此问题,不是这个原因。
(3)事务管理问题
这里我查询了相关资料,得知在方法上添加事务,事务只会对一个数据源进行事务管理。其实说得通俗易懂一点就是,一个数据库的事务管不住另一个数据库的事务。
ok,问题找到现在开始解决问题。
问题解决
根据我这问题产生原因,思路很简单,对每个数据源数据获取单独使用事务管理,这里可以了解一下spring的事务传播机制,默认传播机制为propagation.required(如果当前没有事务,就新建一个事务,如果已
经存在一个事务中,加入到这个事务中),所以在我前面使用方法代理排查问题的时候,还是不行,因为使用的默认传播机制。
这里补充一下事务传播机制:
| propagation_required | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。- 默认 |
|---|---|
| propagation_supports | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
| propagation_mandatory | 使用当前的事务,如果当前没有事务,就抛出异常。 |
| propagation_requires_new | 新建事务,如果当前存在事务,把当前事务挂起。 |
| propagation_not_supported | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
| propagation_never | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
| propagation_nested | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作 |
基于上面提到的事务传播机制,我这将对数据库的操作封装成独立方法,然后我使用propagation_requires_new传播机制,新建事务,使用方式@transactional(propagation = propagation.requires_new)。然后再次测试功能,发现报另一个错了,这就说明这个多数据源失效问题,已经解决。我这的另一个错产生原因主要是项目中使用到了neo4j,而这个事务只支持默认事务,所以报错。
问题解决其他思路
我这因为neo4j不适合使用多个事务进行事务管理。所以我这将代码逻辑进行了处理,我将接口的入口方法,单独封装方法,然后将数据进行业务逻辑处理后,统一添加到数据库和neo4j中,这里我将数据添加逻辑单独封装方法进行处理,最后问题解决,功能测试通过。
其实也可以在代码中不使用@transcational注解,可以在代码块中手动开启提交回滚事务,也可以达到效果。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论