Java 在 Spring 3/Hibernate 中回滚事务的最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4402506/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best practices for rolling back transactions in Spring 3/Hibernate
提问by Corey
Referencing Spring documentation:
参考Spring 文档:
Any RuntimeException will trigger rollback, and any checked Exception will not
任何 RuntimeException 都会触发回滚,任何已检查的 Exception 都不会
Referencing javapractices.com
Unchecked exceptions :
- represent?defects in the program (bugs)?- often invalid arguments passed to a non-private method. To quote from?The Java Programming Language, by Gosling, Arnold, and Holmes : "Unchecked runtime exceptions represent conditions that, generally speaking, reflect errors in your program's logic and cannot be reasonably recovered from at run time."
- are subclasses of?RuntimeException, and are usually implemented using?IllegalArgumentException,?NullPointerException, or?IllegalStateException
- a method is?not?obliged to establish a policy for the unchecked exceptions thrown by its implementation (and they almost always do not do so)
Checked exceptions :
- represent invalid conditions in areas outside the immediate control of the program (invalid user input, database problems, network outages, absent files)
- are subclasses of Exception
- a method is obliged to establish a policy for all checked exceptions thrown by its implementation (either pass the checked exception further up the stack, or handle it somehow)
未经检查的异常:
- 代表?程序中的缺陷(错误)? - 通常传递给非私有方法的无效参数。引用自?Gosling、Arnold 和 Holmes 撰写的《Java 编程语言》:“未经检查的运行时异常表示一般来说反映程序逻辑中的错误并且无法在运行时合理恢复的情况。”
- 是?RuntimeException 的子类,通常使用?IllegalArgumentException、?NullPointerException 或?IllegalStateException 实现
- 一个方法没有义务为它的实现抛出的未经检查的异常建立一个策略(他们几乎总是不这样做)
检查异常:
- 表示程序直接控制之外区域的无效条件(无效的用户输入、数据库问题、网络中断、文件缺失)
- 是 Exception 的子类
- 方法必须为其实现抛出的所有已检查异常建立策略(将已检查异常进一步向上传递堆栈,或以某种方式处理它)
If during my business logic I discover a problem and I want to rollback the changes, I have to throw a new RuntimeException? It's not really a RuntimeException (unchecked exception) since I've identified it in the logic. Or perhaps I'm misunderstanding these concepts?
如果在我的业务逻辑中我发现了一个问题并且我想回滚更改,我必须抛出一个新的 RuntimeException?它不是真正的 RuntimeException(未经检查的异常),因为我已经在逻辑中识别了它。或者也许我误解了这些概念?
My real question, what's best practices for rolling back a transaction in my @Transactional service methods?
我真正的问题是,在我的 @Transactional 服务方法中回滚事务的最佳实践是什么?
采纳答案by Affe
If you're using checked exceptions you simply add them to the rollbackFor
property of your @Transactional
annotation.
如果您使用受检异常,只需将它们添加到注释的rollbackFor
属性中即可@Transactional
。
@Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class })
public void method() throws MyInvalidUserException, MyApplicationException {
...
...
}
etc.
等等。
org.life.java'sanswer also works fine. It's an academic decision if you want to intermix programmatic transaction management into your declarative transactions or keep it strictly declarative.
org.life.java 的答案也很好用。如果您想将程序化事务管理混合到声明式事务中或保持严格声明式,这是一个学术决定。
回答by Jigar Joshi
It should be like
它应该像
@Transactional
public void method () throws YourCustomException {
try{
//logic
}catch(Exception ex){
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
throw(new YourCustomException(ex.getMessage()));
}
}
回答by meriton
I think it's safe to say that there are different opinions about which exceptions should be checked. For instance, consider this excerpt from Introduction to the Spring Framework:
我认为可以肯定地说,对于应该检查哪些异常存在不同的意见。例如,请考虑Spring Framework 简介中的这段摘录:
The Spring data access exception hierarchy is based on unchecked (runtime) exceptions. Having worked with Spring on several projects I'm more and more convinced that this was the right decision.
Data access exceptions not usually recoverable. For example, if we can't connect to the database, a particular business object is unlikely to be able to work around the problem. One potential exception is optimistic locking violations, but not all applications use optimistic locking. It's usually bad to be forced to write code to catch fatal exceptions that can't be sensibly handled. Letting them propagate to top-level handlers like the servlet or EJB container is usually more appropriate. All Spring data access exceptions are subclasses of DataAccessException, so if we do choose to catch all Spring data access exceptions, we can easily do so.
Note that if we do want to recover from an unchecked data access exception, we can still do so. We can write code to handle only the recoverable condition. For example, if we consider that only an optimistic locking violation is recoverable, we can write code in a Spring DAO as follows:
try { // do work } catch (OptimisticLockingFailureException ex) { // I'm interested in this } If Spring data access exceptions were checked, we'd need to write the following code. Note that we could choose to write this anyway:
try { // do work } catch (OptimisticLockingFailureException ex) { // I'm interested in this } catch (DataAccessException ex) { // Fatal; just rethrow it } One potential objection to the first example - that the compiler can't enforce handling the potentially recoverable exception - applies also to the second. Because we're forced to catch the base exception (DataAccessException), the compiler won't enforce a check for a subclass (OptimisticLockingFailureException). So the compiler would force us to write code to handle an unrecoverable problem, but provide no help in forcing us to deal with the recoverable problem.
Spring's use of unchecked data access exceptions is consistent with that of many - probably most - successful persistence frameworks. (Indeed, it was partly inspired by JDO.) JDBC is one of the few data access APIs to use checked exceptions. TopLink and JDO, for example, use unchecked exceptions exclusively. Hibernate switched from checked to unchecked exceptions in version 3.
Spring 数据访问异常层次结构基于未检查(运行时)异常。在多个项目中与 Spring 合作后,我越来越相信这是一个正确的决定。
数据访问异常通常不可恢复。例如,如果我们无法连接到数据库,则特定业务对象不太可能解决该问题。一种潜在的例外是乐观锁定违规,但并非所有应用程序都使用乐观锁定。被迫编写代码来捕获无法合理处理的致命异常通常是不好的。让它们传播到 servlet 或 EJB 容器等顶级处理程序通常更合适。所有 Spring 数据访问异常都是 DataAccessException 的子类,所以如果我们选择捕获所有 Spring 数据访问异常,我们可以很容易地做到这一点。
请注意,如果我们确实想从未经检查的数据访问异常中恢复,我们仍然可以这样做。我们可以编写代码来仅处理可恢复的情况。例如,如果我们认为只有乐观锁违规是可恢复的,我们可以在 Spring DAO 中编写如下代码:
try { // do work } catch (OptimisticLockingFailureException ex) { // 我对此很感兴趣 } 如果检查了 Spring 数据访问异常,我们需要编写以下代码。请注意,我们可以选择这样写:
try { // 做工作 } catch (OptimisticLockingFailureException ex) { // 我对此很感兴趣 } catch (DataAccessException ex) { // Fatal; 只需重新抛出它 } 对第一个示例的一个潜在反对意见 - 编译器无法强制处理潜在的可恢复异常 - 也适用于第二个示例。因为我们被迫捕获基本异常 (DataAccessException),所以编译器不会强制检查子类 (OptimisticLockingFailureException)。所以编译器会强迫我们编写代码来处理不可恢复的问题,但不会提供任何帮助来迫使我们处理可恢复的问题。
Spring 对未经检查的数据访问异常的使用与许多(可能是最成功的)持久性框架一致。(事实上,它部分受到 JDO 的启发。)JDBC 是少数使用检查异常的数据访问 API 之一。例如,TopLink 和 JDO 专门使用未经检查的异常。Hibernate 在版本 3 中从检查异常切换到未检查异常。
Data access exceptions are clearly outside the immediate control of the program, so according to javapractices, they should be checked. But the people at spring source differ. And I trust their judgment more than javapractices.
数据访问异常显然不在程序的直接控制范围内,所以按照javapractices,应该进行检查。但是泉源的人就不同了。而且我比 javapractice 更相信他们的判断。
Therefore, I see nothing wrong with throwing an unchecked exception to indicate that the transaction should be rolled back. Of course, you can also use checked exceptions, and configure the aspect to roll back for them, too. (see Affe's answer for details)
因此,我认为抛出未经检查的异常以指示应回滚事务没有任何问题。当然,您也可以使用已检查的异常,并配置方面为它们回滚。(详见 Affe 的回答)
回答by Ashoka
Came across this url for handling checked & unchecked exceptions , managing transactions: It's not the annotation driven approach but it's good.
遇到了这个用于处理已检查和未检查异常、管理事务的 url:这不是注释驱动的方法,但它很好。
回答by Tomasz
Either roll back programmatically from within:
从内部以编程方式回滚:
@Transactional
public void commit() {
try {
// some business logic...
} catch (ConstraintViolationException e) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
or mark the exception for rollback and handle it from the caller:
或标记回滚异常并从调用者处理它:
@Transactional(rollBackFor = TransactionException.class)
public void commit() throws ConstraintViolationException{
try {
// some business logic...
} catch (ConstraintViolationException e) {
// handle the exception
// re-throw for rollback
new TransactionException(e);
}
}
public void doCommit(){
try {
commit()
} catch (TransactionException e){
// do nothing as already handled
}
}
I prefer the former as it keeps the code simpler, but it is discouragedaccording to Spring docs:
我更喜欢前者,因为它使代码更简单,但根据 Spring 文档,不鼓励这样做:
Programmatic rollback is available should you absolutely need it, but its usage flies in the face of achieving a clean POJO-based architecture.
如果您绝对需要它,则可以使用编程回滚,但它的使用与实现基于 POJO 的干净架构背道而驰。