0

事务嵌套导致transaction rolled back because it has been marked as rollback-利来国际app

一叶扁舟 2021-11-21
197

一、问题描述

事务的注解使用起来很简单,但是如果只了解皮毛就会出现事务失效、事务异常等问题。

关于事务失效场景,我在这篇《为什么你的事务不好使?一下解决java中n种事务失效场景》文章中记录了多种失效场景,这里就不再赘述。

本次主要讲,在事务嵌套(加了事务的方法,调用加了事务的方法)时,报错

transaction rolled back because it has been marked as rollback-only, org.springframework.transaction.unexpectedrollbackexception: transaction rolled back because it has been marked as rollback-only

二、问题产生原因

2.1、问题复现

如下,在classa类中有个加了事务的a方法,调用了classb中的加了事务的b方法

public class classa { private classb classb; @transactional public void a() { try { b(); } catch (exception e) { log.error("啥也不干"); } } } public class classb { @transactional public void b() { throw new exception(); } }

这种情况下就会报错:transaction rolled back because it has been marked as rollback-only

2.2、报错原因

当a方法的事物(required),b方法的事物(required),a调用b方法,在spring中,spring将会把这些事务合二为一。

当整个方法中每个子方法没报错时,整个方法执行完才提交事务。

如果某个子方法有异常,spring将该事务标志为rollback only。如果这个子方法没有将异常往上抛,或者主父方法将子方法抛出的异常捕获了,那么,该异常就不会触发事务进行回滚,事务就会在整个方法执行完后就会提交,这时就会造成transaction rolled back because it has been marked as rollback-only的异常。(由于异常被标记了rollback only,但是又执行了commit,此时就会报这个错

三、解决方法

  • 方法1:父方法不要捕获异常

    在2.1的举例中,a方法去掉try…catch即可

  • 方法2:子方法的事务propagation属性换为nested

    在2.1的举例中,将b方法的事务注解的属性改为nested

    public class classb { @transactional(propagation = propagation.nested) public void b() { throw new exception(); } }
属性 功能描述
propagation.nested 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为和 propagation.required 效果一样。
「喜欢文章,快来给作者赞赏墨值吧」
【利来手机国际的版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:[email protected]进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论