Transaction rolled back because

2019-07-16  本文已影响0人  猫尾草

1. 问题

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

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

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

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

2. 发生问题的原因

  @Transactional(propagation= Propagation.REQUIRED):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是@Transactional的默认方式。裸的@Transactional注解就是这种方式。
  在这种情况下,外层事务(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,意思是“事务已经被标记为回滚,无法提交”。

3. 解决方法

记录下手动回滚

// 回滚整个方法
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

// 回滚指定的一段操作
// 设置回滚点
Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
// 回滚到回滚点
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
上一篇下一篇

猜你喜欢

热点阅读