美文网首页
Transaction rolled back because

Transaction rolled back because

作者: 饱饱想要的灵感 | 来源:发表于2024-09-19 09:25 被阅读0次

一、 问题描述

两个使用@Transaction注解的Service,A和B,在A中引入了B的方法用于更新数据 ,当A中捕捉到B中有异常时,回滚动作正常执行,但是当return时则出现 org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only 异常。
代码示例:

@Service
public class ServiceA {
  @Autowired
  private ServiceB serviceB;

  @Transactional
  public void methodA() {
    try{
      serviceB.methodB();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

@Service
public class serviceB {
  @Transactional
  public void methodB() {
    throw new RuntimeException();
  }
}

二、问题分析

@Transactional的默认方式为@Transactional(propagation= Propagation.REQUIRED):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

在这种情况下,外层事务(ServiceA)和内层事务(ServiceB)就是一个事务,任何一个出现异常,都会在methodA执行完毕后回滚。
  
如果内层事务B抛出异常e(没有catch,继续向外层抛出),在内层事务结束时,spring会把事务B标记为“rollback-only”。
这时外层事务A发现了异常e,如果外层事务A catch了异常并处理掉,那么外层事务A的方法会继续执行代码,直到外层事务也结束。
外层事务A结束后想commit,因为正常结束没有向外抛异常,但是内外层事务AB是同一个事务,事务B(同时也是事务A)已经被内层方法标记为“rollback-only”,需要回滚,无法commit。

因此spring就抛出了异常org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only,意思是“事务已经被标记为回滚,无法提交”。

三、解决方法

  1. methodB和methodA放在同一个service中(这个不大现实, 也不符合代码规范);

  2. 外层事务不使用try-catch代码块, 让其自然抛出异常;

  3. 在内层事务中做异常捕获处理,并且不向外抛异常;

  4. 在内层事务中做手动回滚, 代码示例:

  // 回滚整个方法
  TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  
  // 回滚指定的一段操作
  // 设置回滚点
  Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
  // 回滚到回滚点
  TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
  1. 推荐:如果希望内层事务回滚,但不影响外层事务提交,需要将内层事务的传播方式指定为@Transactional(propagation= Propagation.NESTED),外层事务的提交和回滚能够控制嵌套的内层事务回滚;而内层事务报错时,只回滚内层事务,外层事务可以继续提交。。

  2. 如果这个异常发生时,内层需要事务回滚的代码还没有执行,则可以@Transactional(noRollbackFor = {内层抛出的异常}.class),指定内层也不为这个异常回滚。

相关文章

网友评论

      本文标题:Transaction rolled back because

      本文链接:https://www.haomeiwen.com/subject/yksoljtx.html