【问题标题】:How to make Spring @Transactional roll back on all uncaught exceptions?如何让 Spring @Transactional 回滚所有未捕获的异常?
【发布时间】:2016-02-05 07:41:56
【问题描述】:

我的 Spring/Java Web 应用程序有@Transactional 可以接触数据库的服务:

@Transactional
public class AbstractDBService  { ... }

所需的功能适用于任何 未捕获 可抛出,它向上传播到服务层之外以导致回滚。有点惊讶这不是默认行为,但经过一番谷歌搜索后:

@Transactional(rollbackFor = Exception.class)

这似乎有效,除非故意吞下异常而不重新抛出异常。 (特殊情况是找不到实体。猜想这可以重新设计为不抛出异常,但预计会不可避免地出现其他异常 - 例如,在使用 Thread.sleep() 时会想到一个 InterruptedException) . 然后 Spring 抱怨:

org.springframework.transaction.TransactionSystemException:无法提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException:事务标记为 仅回滚 ...被截断了.. 引起:javax.persistence.RollbackException:事务标记为rollbackOnly 在 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:58) 在 org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)

我在这里遗漏了什么吗?...有没有办法告诉 Spring 回滚所有未捕获的 throwables

【问题讨论】:

  • 我很困惑。您当前的rollbackFor 应该会导致@Transactional 代理回滚从注释方法中抛出的任何Exception。这不是你看到的吗?
  • 我看到了,但它似乎在这样的Exception 被捕获而不是重新抛出时进行了失败的回滚尝试。 (This answer 似乎支持这一点。)

标签: java spring hibernate jpa transactions


【解决方案1】:

如果要回滚所有未捕获的 Throwable,可以在注解中指定:

@Transactional(rollbackFor = Throwable.class)

默认情况下,Spring 不会为 Error 子类回滚,可能是因为一旦抛出错误,JVM 将处于足够好的状态以对其进行任何处理似乎令人怀疑,此时事务可能会超时. (如果您在引发 OutOfMemoryError 时尝试回滚,最有可能的结果是另一个 OutOfMemoryError。)因此您可能不会从中获得太多收益。

当您提到吞下异常的情况时,不可能期望 Spring 知道它,因为异常没有找到通往 Spring 代理(实现事务功能)的途径。这就是您的 RollbackException 示例中发生的情况,Hibernate 已经确定事务需要回滚,但 Spring 没有收到备忘录,因为有人吃掉了异常。所以 Spring 并没有回滚事务,它认为一切正常并尝试提交,但由于 Hibernate 将事务标记为仅回滚,因此提交失败。

答案是不要吞下这些异常,而是让它们被抛出;不检查它们应该使您更容易做正确的事情。应该设置一个异常处理程序来接收从控制器抛出的异常,在应用程序的任何级别抛出的大多数异常都可以在那里捕获并记录。

【讨论】:

  • 非常感谢您的详细回答。对 Spring 如何在引擎盖下工作的一些很好的见解 - 对我来说,这都是“魔法”……但是一旦你开始寻找,猜测某些类型的魔法是可能的,而有些则不是!仍然认为这有点可惜,但如果例如第三方实用程序库用于抛出我们不关心并想要吞下并继续的异常。好的,可以开始为特定异常添加noRollbackFor,但如果它是一种广泛常见的异常类型怎么办?...无论如何,这有点假设,听起来像是架构限制。
  • @Steve:你仍然可以做任何你需要的异常处理,包括吃掉异常。请注意您希望对当前交易产生什么影响。顺便说一句,默认情况下 spring 允许您避免回滚检查异常。 (实际上,默认值在很多情况下都非常有效,正如我在第一部分中关于回滚错误所描述的那样。)
猜你喜欢
  • 2019-06-30
  • 2018-01-17
  • 1970-01-01
  • 2020-10-18
  • 2015-02-12
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多