链式方法调用的事务问题剖析

最近做了分布式的项目,当然没有设计分布式事务的处理,一条逻辑线太长,方法调方法,所以之间的事务问题就暴露出来了
我已阵亡,直接码代码吧


 

@Service
public class TransactionalServiceImpl implements TransactionalService {

    @Autowired
    private CgpMngUserbraService cgpMngUserbraService;

    @Transactional
    @Override
    public void method() {
        CgpMngUserbra cgpMngUserbra = cgpMngUserbraService.selectUserBraRules(0, 0);
        if (null == cgpMngUserbra) {
            cgpMngUserbraService.insertUserBraRules(0, 0, "method");
        }
        method2();
    }

//    @Transactional//此处事务不会生效,原因可阅读上一篇博客
//    传送门---> https://blog.csdn.net/fanxb92/article/details/81296005
    public void method2() {
        CgpMngUserbra cgpMngUserbra = cgpMngUserbraService.selectUserBraRules(0, 0);
        if (null == cgpMngUserbra) {
            cgpMngUserbraService.insertUserBraRules(0, 0, "method2");
        }
        TransactionalServiceImpl transactionalService = (TransactionalServiceImpl) AopContext.currentProxy();
        transactionalService.method3();
    }

    @Transactional
//    @Transactional(propagation = Propagation.REQUIRES_NEW)
//    @Transactional(propagation = Propagation.NESTED)
    public void method3() {
        CgpMngUserbra cgpMngUserbra = cgpMngUserbraService.selectUserBraRules(0, 0);
        if (null == cgpMngUserbra) {
            cgpMngUserbraService.insertUserBraRules(0, 0, "method3");
        }
    }
}

先介绍一下测试逻辑:

1、method,method2,method3三个方法都会在一张表保存同一条数据,并且链式调用。

2、method2加事务是不生效的,method2中事务和method中保持一致,参照代码中博客链接。

3、下面是测试级联事务,method3上面三种事务处理方式

  • 第一种@Transactional,method3中事务和前面保持一致(method方法上注解产生的事务中),全部执行完毕,数据库中一条数据(createdBy = 'method')。一定是全部执行完毕哦,中途打断点,method中还为插入到数据库,因为方法未结束,未commit。
  • 第二种@Transactional(propagation = Propagation.REQUIRES_NEW),method3开启了一个新的事务,会将已有的事务挂起,

同样,方法全部执行完毕后数据库两条数据,数据库记录截图如下:

可见,是method中数据入库时间在前,分析===>
!!!!!!!!!此处非常重要,可能说的不太简洁精确,仔细体会!!!!!!!!!!!!!!!!!!

method中执行insert(此时会插入第一条数据createdBy = 'method'),在方法未执行结束时未commit,数据库中无插入记录,但是在缓存中存在。

method2方法嵌套在method方法中,在同一事务中,method2方法中会查询到记录,所以不会再插入数据。

method3方法嵌套在method2方法中,开启了新的事务,不会查询到method方法事务中的数据,所以会执行insert(插入第二条数据createdBy = 'method3')。

此处是细节哦!!!>>>>>>method3方法开启新事务,方法执行完毕就会提交,
可在method3结束但method未结束的地方打断点,会看到数据库已经有记录了(createdBy = 'method3')。
放开断点,全部执行完毕,数据库有两条记录,如前面的截图。
可见级联开启新事务是可以的,但一定要调用外部外方法才会生效,或者使用AopContext.currentProxy()。
  • 第三种@Transactional(propagation = Propagation.NESTED)

抛出异常JpaDialect does not support savepoints - check your JPA provider's capabilities
public JpaTransactionManager() {setNestedTransactionAllowed(true);}

后来才知道Hibernate也不支持Nested Transaction,测试不了,只能用jdbc事务了,使用JdbcTemplate。

好吧,就先聊这么多吧。谢谢阅读。

猜你喜欢

转载自blog.csdn.net/fanxb92/article/details/82784348