回滚一个被 @Transactional 注解的方法

17

您好。以下是代码:

 class A{
     private B b;
    @Transactional
    public SomeResult doSomething(){
        SomeResult res = null;
        try {
          // do something 
        } catch (Exception e) {
            res  = b.saveResult();
        }
        return res ;
    }
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
class B{
  public SomeResult saveResult(){
      // save in db 
  }
}

据我理解,如果在方法doSomething中出现异常,事务不会回滚。如何使其回滚并返回SomeResult呢?

2个回答

26

你不应该通过编程方式调用Rollback函数。最好的方法是使用声明式方法,就像文档推荐的那样。为此,您需要注释哪些异常将触发回滚。

在您的情况下,可以使用以下代码:

@Transactional(rollbackFor={MyException.class, AnotherException.class})
public SomeResult doSomething(){
   ...
}

请参考@Transaction API, 以及有关事务回滚的文档。

如果您想要编程式地进行事务回滚,尽管不推荐这么做,请像已经建议的那样从TransactionAspectSupport中调用。这是文档中的描述:

public void resolvePosition() {
  try {
    // some business logic...
  } catch (NoProductInStockException ex) {
    // trigger rollback programmatically
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}

可能存在架构错误。如果您的方法失败并且需要抛出异常,您不应该期望它返回任何内容。也许您为这个方法分配了过多的职责,应该创建一个单独的方法来仅对数据进行建模,并在出现问题时抛出异常并回滚事务。无论如何,请阅读文档。


TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();仍然会抛出异常!我该如何从我的事务方法中返回一些东西? - Guillaume Polet
要使用TransactionAspectSupport,必须确保方法/类上没有@Transactional注释。不幸的是,这是一种hack方法。一个新的方法会更加清晰。 - MovieMe

3
使用TransactionAspectSupport.currentTransactionStatus()获取事务状态,将事务管理器注入到您的bean中,尝试在事务管理器中调用Rollback(DefaultTransactionStatus status)。请参考Spring 文档
强烈建议您尽可能使用声明性方法进行回滚。如果绝对需要,可以使用编程式回滚,但其使用与实现干净的基于POJO的体系结构相违背。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接