链式方法调用的事务问题剖析
最近做了分布式的项目,当然没有设计分布式事务的处理,一条逻辑线太长,方法调方法,所以之间的事务问题就暴露出来了
我已阵亡,直接码代码吧
@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。
好吧,就先聊这么多吧。谢谢阅读。