一、问题描述
事务的注解使用起来很简单,但是如果只了解皮毛就会出现事务失效、事务异常等问题。
关于事务失效场景,我在这篇《为什么你的事务不好使?一下解决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 效果一样。 |
「喜欢文章,快来给作者赞赏墨值吧」
【米乐app官网下载的版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。