如何使Spring @Transactional回滚所有未捕获的异常? [英] How to make Spring @Transactional roll back on all uncaught exceptions?

查看:309
本文介绍了如何使Spring @Transactional回滚所有未捕获的异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Spring / Java web应用程序具有 @Transactional 服务,  @Transactional 
public class AbstractDBService {...}

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

  @Transactional(rollbackFor = Exception。类)

这似乎工作,除非故意吞下异常并且不会重新排除异常。 (特殊情况是没有找到实体的时候,猜猜这可能是重新设计的,不会抛出一个异常,但期望不可避免地会出现其他异常 - 例如,一个想到的是 InterruptedException code>当使用 Thread.sleep())。然后Spring抱怨:


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

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

解决方案

如果您想要在所有未捕获的Throwables上回滚,在注释中:

  @Transactional(rollbackFor = Throwable.class)

默认情况下,Spring不会针对Error子类进行回滚,可能是因为一旦抛出一个JVM将会出现的错误无论如何,这是一个足够好的状态来做任何事情,在这一点上交易可以超时。 (如果在发生OutOfMemoryError时尝试回滚,最有可能的结果是另一个OutOfMemoryError。)所以你可能没有太多的收获。



当你提到这个例子吞噬一个异常,Spring就没有办法知道它,因为这个异常没有找到Spring的代理(它正在实现事务功能)。这就是你的RollbackException例子中发生的事情,Hibernate已经计算出需要回滚的事务,但是Spring没有得到备忘录,因为有人吃掉了异常。所以Spring并没有回滚事务,它认为一切正常并且尝试提交,但是由于Hibernate已经标记了事务回滚,提交失败。



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


My Spring/Java web application has @Transactional services that can touch the database:

@Transactional
public class AbstractDBService  { ... }

Desired functionality is for any uncaught throwable that propagates up beyond the service layer to cause a rollback. Was a bit surprised this isn't the default behaviour but after a bit of googling tried:

@Transactional(rollbackFor = Exception.class)

This seems to work except when an exception is deliberately swallowed and not rethrown. (The particular case is when an entity is not found. Guess this could be redesigned to not throw an Exception but expect there will inevitably be others - e.g. one that springs to mind is an InterruptedException when using Thread.sleep()). Then Spring complains:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly ...truncated.. Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:58) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)

Am I missing something here?... Is there a way to tell Spring to rollback on all uncaught throwables?

解决方案

If you want to rollback on all uncaught Throwables, you can specify that in the annotation:

@Transactional(rollbackFor = Throwable.class)

By default Spring doesn't rollback for Error subclasses, probably because it seems doubtful once an Error is thrown that the JVM will be in a good enough state to do anything about it anyway, at that point the transaction can just time out. (If you try to rollback when an OutOfMemoryError is raised, the most likely outcome is another OutOfMemoryError.) So you may not gain much with this.

When you mention the case of swallowing an exception, there's no way Spring can be expected to know about it because the exception is not finding its way to Spring's proxy (which is implementing the transactional functionality). This is what happens in your RollbackException example, Hibernate has figured out the transaction needs to rollback but Spring didn't get the memo because somebody ate the exception. So Spring isn't rolling the transaction back, it thinks everything is ok and tries to commit, but the commit fails due to Hibernate having marked the transaction rollback-only.

The answer is to not swallow those exceptions but let them be thrown; making them unchecked is supposed to make it easier for you to do the right thing. There should be an exception handler set up to receive exceptions thrown from the controllers, most exceptions thrown at any level of the application can be caught there and logged.

这篇关于如何使Spring @Transactional回滚所有未捕获的异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆