在观看此篇文章以前须要了解什么是事务的传播属性git
在观看此篇文章以前须要了解什么是事务的传播属性github
在观看此篇文章以前须要了解什么是事务的传播属性post
Transaction rolled back because it has been marked as rollback-only3d
相信你们在使用Spring事务的时候有几率会碰到一个异常,这个异常就是UnexpectedRollbackException
异常的描述就是上面所写的。至于这个异常是怎么报出来的呢?咱们先模拟出来,而后进行着手分析。咱们模拟的场景是转钱的场景,即A给B转100块钱。code
@Service public class UserAccountA { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private UserAccountB userAccountB; @Transactional public void eventTwo() throws RollbackException { jdbcTemplate.execute("UPDATE USER SET MONEY = MONEY - 100 WHERE NAME = 'A'"); userAccountB.eventTwo(); } }
@Service public class UserAccountB { @Autowired private JdbcTemplate jdbcTemplate; @Transactional(propagation = Propagation.REQUIRED,rollbackFor = RollbackException.class) public void eventTwo() throws RollbackException { jdbcTemplate.execute("UPDATE USER SET MONEY = MONEY + 100 WHERE NAME = 'B'"); throw new RollbackException(); } }
public class RollbackException extends Exception { }
上面的三个类分别是用户A、用户B、和自定义的异常。这时候咱们运行程序的时候就能看到那个异常了。那么为何会报此异常呢。这里咱们有两个须要注意的点。blog
Propagation.REQUIRED
此传播属性下的意思就是支持当前事务,若是当前没有事务那么就新建事务,若是有事务就加入此事务。因此此时B方法加入到了A方法建立的事务中Exception
。下面的是官方文档的一句话,意思就是默认状况下当抛出RuntimeException
才会回滚。By default, a transaction will be rolling back RuntimeException and Error继承
有了上面两个知识的补充,下面咱们开始讲为何会报这个异常,咱们都知道Spring的事务实际上是用了动态搭理的原理实现的。事务
大概嵌套逻辑就像上图同样,可是在B方法执行完成之后抛出了异常,须要回滚,可是并不会真正的回滚,而是将此事务标记为rollback-only
,当A方法执行完之后,咱们能够看到在A方法上面并无rollbackFor
这个参数设置,而抛出的异常也是继承了Exception
因此A方法执行完之后想要提交事务,因此此时就会产生冲突。文档
同一个事务中,一个方法想要回滚,一个方法想要提交。固然会抛异常了。get
解决办法很简单,首先咱们看是什么致使了这个问题。同一个事务中,一个方法想要回滚,一个方法想要提交。。致使这个问题缘由有两个。
因此针对上面缘由咱们能够有两种不一样的解决方法。
PROPAGATION_REQUIRES_NEW
,即不会和A共用一个事务,会本身新启动一个事务。此时A和B两个方法互不干扰。rollbackFor = RollbackException.class
参数,此时A方法收到B方法抛出的异常后,也会回滚了。