问题描述

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;
    }
最后修改:2024 年 11 月 29 日
感恩的心,感谢有你!