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

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


 

@Service
public class TransactionalServiceImpl implements TransactionalService {

    @Autowired
    private CgpMngUserbraService cgpMngUserbraService;

    @Transactional
    @Override
    public void method() {
        List<CgpMngUserbra> cgpMngUserbras = cgpMngUserbraService.selectUserBraRules(0, 0);
        if (null == cgpMngUserbras || 0 == cgpMngUserbras.size()) {
            cgpMngUserbraService.insertUserBraRules(0, 0, "method");
        }
        method2();
    }

//    @Transactional//此处事务不会生效,原因可阅读上一篇博客
//    传送门---> https://blog.****.net/fanxb92/article/details/81296005
    public void method2() {
        List<CgpMngUserbra> cgpMngUserbras = cgpMngUserbraService.selectUserBraRules(0, 0);
        if (null == cgpMngUserbras || 0 == cgpMngUserbras.size()) {
            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() {
        List<CgpMngUserbra> cgpMngUserbras = cgpMngUserbraService.selectUserBraRules(0, 0);
        if (null == cgpMngUserbras || 0 == cgpMngUserbras.size()) {
            cgpMngUserbraService.insertUserBraRules(0, 0, "method3");
        }
    }
}

先介绍一下测试逻辑:method,method2,method3三个方法都会在一张表保存同一条数据,并且链式调用。

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

method3上面三种事务处理方式
第一种@Transactional,method3中事务和前面保持一致(method方法上注解产生的事务中),全部执行完毕,数据库中一条数据。
一定是全部执行完毕哦,中途打断点,method中还为插入到数据库,因为方法未结束,未commit。

第二种@Transactional(propagation = Propagation.REQUIRES_NEW),method3开启了一个新的事务,会将已有的事务挂起,
同样,方法全部执行完毕后数据库两条数据,数据库记录截图如下:
链式方法调用的事务问题剖析
可见,是method中数据入库时间在前,分析===>
!!!!!!!!!此处非常重要,可能说的不太简洁精确,仔细体会!!!!!!!!!!!!!!!!!!

method中执行insert,但未commit,未插入到数据库
method3中执行insert,执行完毕commit,数据库中会先插入记录(在method3结束但method未结束的地方打断点,会看到数据库已经有记录了),
同时method方法也结束,method事务commit,数据库中插入记录。(method3是新事务,同一事务会查询缓存,所以不在同一个事务中也没有啦,查询数据库是没有记录的,也会入库)。

开启新事务,方法执行完毕就会提交,数据库中有记录,与前面事务不影响。但插入时间,看代码具体逻辑,在前的插入时间在前。

第三种@Transactional(propagation = Propagation.NESTED)
抛出异常JpaDialect does not support savepoints - check your JPA provider's capabilities
public JpaTransactionManager() {setNestedTransactionAllowed(true);}

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

 

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