Spring中的@Transactional注解为什么要加rollbackFor = Exception.class之源码解析

       开发过程中,经常需要对service层的方法加事务注解@Transactional,以确保数据库数据的前后一致以及数据安全。但是发现不少项目中只加了@Transactional注解,并没有rollbackFor = Exception.class这个属性,那么不加这个属性,有些异常,事务管理器是不会对此异常做回滚操作的。

       先定结论,再做验证:当只加@Transactional注解时,那么业务代码抛RuntimeException和Error时,事务管理器会识别到这类异常来进行回滚,但是非RuntimeException的异常抛出时,事务管理器是不会回滚事务的。如果加了属性rollbackFor = Exception.class,那么事务管理器会捕获到Exception及子类的所有异常和Error来回滚事务。

      异常的分类请看其它文章,在此不做详解。

以下用源码来做验证解析:

1 自己业务代码,主要目的是让抛一个非RuntimeException的异常。


    
    
  1. @Transactional(rollbackFor = Exception.class)
  2. @Override
  3. public TestUser updateTemp (String pass) throws IOException {
  4. TestUser t = new TestUser();
  5. t.setCreator(pass);
  6. t.setId( 1);
  7. userMapper.updateByPrimaryKeySelective(t);
  8. InputStream fis = new BufferedInputStream( new FileInputStream( "c"));
  9. byte[] buffer = new byte[fis.available()];
  10. fis.read(buffer);
  11. fis.close();
  12. TestUser t1 = new TestUser();
  13. t1.setId( 1);
  14. return userMapper.selectOne(t1);
  15. }

2 加了@Transactional时,请求service时,会调用以下方法:


    
    
  1. org.springframework.transaction.interceptor.TransactionInterceptor
  2. @Override
  3. @Nullable
  4. public Object invoke (MethodInvocation invocation) throws Throwable {
  5. // Work out the target class: may be {@code null}.
  6. // The TransactionAttributeSource should be passed the target class
  7. // as well as the method, which may be from an interface.
  8. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
  9. // Adapt to TransactionAspectSupport's invokeWithinTransaction...
  10. return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
  11. }

3 继续跟进方法completeTransactionAfterThrowing(txInfo,ex):

4 继续追踪这个方法 txInfo.transactionAttribute.rollbackOn(ex):

 5 如果事务注解加了rollbackFor=Exception.class属性,那么rollbackRules这个集合不会为空,导致winner不会为空,且winner的属性为RollbackRuleAttribute,这个方法最终返回true。rollbackFor=Exception.class这个属性直接决定着winner是否为空。

 

 如果rollbackRules为空,则winner为空,那么会按照以下路径执行:

 

 从上图可以看出,如果没有rollbackFor=Exception.class属性,那么抛出的异常属于RuntimeException和Error时,这个方法才会返回true。这两个类型外的异常被抛出时,返回的是false。

 6  如果以上5步骤返回true,返回 步骤3 中的completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex),事务管理器会回滚事务。如果以上5步骤返回的是false,则事务管理器会提交事务。

总结:@Transactional事务的属性 rollbackFor=Exception.class 是否存在决定着 List<RollbackRuleAttribute> rollbackRules 是否为空。如果rollbackFor=Exception.class 存在,那么抛出的所以异常就能被事务管理器识别并回滚事务(步骤5),反之事务管理器只会去识别RuntimeException及其子类和Error的异常去回滚(步骤5),其它异常抛出时不能被回滚。切记如果rollbackFor=xxx.class 存在时,且xxx.class并不一定是Exception.class,那么事务也不一定会回滚。主要是抛的异常一定要属于xxx.class,才能回滚。

来源:https://blog.csdn.net/jll126/article/details/108637372
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值