0


SpringBoot多数据源@DS和@Transactional冲突

背景介绍

  1. 因为一次项目中使用 @DS 注解实现多数据源切换时,在一个controller中同时操作多个数据源的service方法,为了保证这一组操作下数据的完整性,则需要使用事务@Transaction进行保证,于是直接在controller方法上加上了该注解,以为没有问题,结果在切换数据源的时候报错找不到另一个数据源的数据表

问题解决

分析解决

现在我们先来看一下,是怎么解决问题的。
首先,在主方法上加 @Transactional(rollbackFor = Exception.class),默认事务的传播机制是,PROPAGATION_REQUIRED ,可以不指定。
然后,在切换数据源的方法类上,添加 @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) ,指定事务的传播机制是,Propagation.REQUIRES_NEW。
至此,冲突解决!

直接上代码

    @Transactional(rollbackFor = Exception.class)
    @DS("db1")
    @Override
    public Result 主方法() {
    }
     @DS("db2")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public void 切换数据源的方法(HtyyOrder htyyOrder) {
    }

原因解析

解决办法就是将原本的一个事务拆分成两个事务。你可以试一下,只在主方法中加事务,你会发现在切面里看数据源切换了,但事务内的数据源依然是旧的,这样就会报出XXX表找不到的问题。那么到底是什么原因导致一个事务内的数据源没有随着@DS(“db2”)注解做出动态数据源切换呢?

  1. 因为SPRING在开启事务的同时,会去数据库连接池拿数据库连接。如果仅在主方法上添加@TRANSACTIONAL,那么,TRANSACTIONINTERCEPTOR 会使用 SPRING DATASOURCETRANSACTIONMANAGER 创建事务,并将事务信息(获取数据源CONNECTION连接,此时获取到的数据源是默认配置的BASE数据源信息)连接信息,通过 THREADLOCAL 绑定在当前线程。
  2. 此时当前线程事务绑定的连接信息是BASE数据源,当我们在内层切换数据源方法上使用@DS切换数据源,并没有重新开启新事务,没有改变当前线程事务的连接信息,仅仅是做了一次拦截,改变了DATASOURCEHOLDER的栈顶DATASOURCE,对于整个事务的连接是没有影响的,所以会产生数据源没有切换的问题。
  3. 所以我这里的解决办法是,将保证住方法操作数据完整性的事务,拆解成两个事务,在切换数据源方法类上,除了添加切换数据源的注解@DS(“DB2”),再添加@TRANSACTIONAL(PROPAGATION = PROPAGATION.REQUIRES_NEW, ROLLBACKFOR = EXCEPTION.CLASS),新建开一个事务,获取新数据源CONNECTION连接。
标签: spring boot java spring

本文转载自: https://blog.csdn.net/mnn12/article/details/136786845
版权归原作者 林知屿 所有, 如有侵权,请联系我们删除。

“SpringBoot多数据源@DS和@Transactional冲突”的评论:

还没有评论