问题描述
jkms项目用到了多数据源。
一个导入接口,需要先查询mysql获取经销商列表,然后查询pgsql获取激活记录,执行一波校验,最后将excel表格解析出来的数据插入到mysql中。
因为有插入,所以要带事务注解回滚。
在同一个数据下,Mapper的@DS注解失效,导致用mysql的驱动去执行pgsql,出现报错
问题原因
- 在开启事务的同时,会从数据库连接池获取数据库连接,一个事务绑定一个连接,一旦绑定后,在整个事务的过程中,使用的数据库连接conn都是同一个。
- Spring中@Transactional是通过APO+ThreadLocal实现的,再被拦截方法主体执行前会通过getConnection获取数据库连接conn保存到ThreadLocal中,然后在执行被拦截的事务方法中对数据进行CRUD时,会再次从 ThradLocal 获取之前创建的connection
如果某个方法没有使用@DS注解标识使用的数据源,会使用默认的数据源 - @DS注解添加在mapper接口上无效
解决方案
- 既然事务开启后无法切换数据源, 那么可以在事务开启前就切换好数据源
- 一个事务只能关联一个数据源,那么可以开启2个事务,关联不同的的数据库
- @DS加在mapper接口上无效,可直接加在方法上
将查询pg库的方法单独抽离,修改事务传播属性,添加@DS("pgsql")即可
@Transactional(propagation = Propagation.REQUIRES_NEW)
@DS("postgres")
public List<String> getDeviceTraceMacList(List<String> deviceMacList){
List<DeviceTrace> deviceTraceList = this.list(new LambdaQueryWrapper<DeviceTrace>().in(DeviceTrace::getDeviceMac, deviceMacList));
List<String> macList = deviceTraceList.stream().map(DeviceTrace::getDeviceMac).toList();
return macList;
}