如何使Spring @Transactional回滚所有未捕获的异常?

时间:2015-11-04 17:24:26

标签: java spring hibernate jpa transactions

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

@Transactional
public class AbstractDBService  { ... }

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

@Transactional(rollbackFor = Exception.class)

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

  

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

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

1 个答案:

答案 0 :(得分:8)

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

@Transactional(rollbackFor = Throwable.class)

默认情况下,Spring不会为Error子类回滚,这可能是因为一旦抛出错误,JVM将处于一个足够好的状态,无论如何都要对它做任何事情似乎都是值得怀疑的,此时事务可以只是超时。 (如果在引发OutOfMemoryError时尝试回滚,最可能的结果是另一个OutOfMemoryError。)因此,您可能无法获得太多收益。

当你提到吞下异常的情况时,Spring无法预料到它会知道它,因为异常没有找到Spring的代理方式(它实现了事务功能) )。这就是你的RollbackException示例中发生的事情,Hibernate已经发现事务需要回滚但是Spring没有得到备忘录,因为有人吃了这个例外。因此Spring不会回滚事务,它认为一切正常并尝试提交,但由于Hibernate标记了仅事务回滚,提交失败。

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