UnexpectedRollbackException会覆盖我自己的异常

时间:2010-07-14 11:56:52

标签: java spring transactions

我对spring的事务管理有以下奇怪的情况:

我有方法A调用方法B,它调用方法C,每个方法都在不同的类中。方法B和C都包含事务。两者都使用PROPAGATION_REQUIRED,因此当spring创建两个逻辑事务时,db中有一个物理事务。

现在,在方法C中,我抛出一个RuntimeException。这将内部逻辑事务设置为rollbackOnly和物理事务。在方法B中,我知道UnexpectedRollbackException的可能性,所以我不进行正常提交。我从C中捕获异常,然后抛出另一个RuntimeException。

我希望外部的RuntimeException会导致回滚到外部事务,但实际行为是这样的:

  • 外部事务似乎尝试提交,或者至少检查其状态,然后抛出UnexpectedRollbackException,因为物理事务已经标记为rollbackOnly。
  • 在抛出该异常之前,它会向日志打印另一个异常,指出“由提交异常覆盖的应用程序异常”。因此,调用者A接收UnexpectedRollbackException,而不是B抛出的异常。

我找到了一个解决方法,就是在抛出异常之前主动将外部事务设置为回滚

public ModelAndView methodB(HttpServletRequest req, HttpServletResponse resp) {
  try{
    other.methodC();
  } catch (RuntimeException e){
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    throw new RuntimeException ("outer exception");
  }
  return handleGetRequest(req, resp);
}

但是,这种解决方法强烈地将代码与事务api结合在一起,我想避免这种情况。有什么建议吗?

P.S。 这两个事务都是为了回滚运行时异常。我没有定义任何rollbackFor异常或类似的东西

2 个答案:

答案 0 :(得分:6)

答案 1 :(得分:5)

您可以尝试在failEarlyOnGlobalRollbackOnly继承者(true)中将AbstractPlatformTransactionManager标记设置为HibernateTransactionManager。这是它的描述:

设置是否在事务全局标记为仅回滚的情况下提前失败。

默认为“false”,仅在最外层的事务边界处导致UnexpectedRollbackException。早在第一次检测到全局回滚标记时,即使在内部事务边界内,也会切换此标志以导致UnexpectedRollbackException。注意,从Spring 2.0开始,全局回滚标记的失败早期行为已经统一:默认情况下,所有事务管理器只会在最外层的事务边界处导致UnexpectedRollbackException。例如,即使在操作失败并且事务永远不会完成之后,这也允许继续单元测试。如果此标志已明确设置为“true”,则所有事务管理器只会提前失败。