回滚声明式事务
前面一节概述了如何在应用中声明式地为类(通常是服务层类)指定事务设置的基础知识。本节描述了如何在 XML 配置中以简单、声明式的方式控制事务的回滚。有关使用 @Transactional
注解声明式控制回滚语义的详细信息,请参阅 @Transactional
设置。
向 Spring Framework 的事务基础设施指示事务工作需要回滚的推荐方式是在当前在事务上下文中执行的代码中抛出一个 Exception
。Spring Framework 的事务基础设施代码会捕获调用栈中冒泡上来的任何未处理的 Exception
,并决定是否将事务标记为回滚。
在其默认配置中,Spring Framework 的事务基础设施代码仅在发生运行时 unchecked 异常时才将事务标记为回滚。也就是说,当抛出的异常是 RuntimeException
的实例或子类时。(默认情况下,Error
实例也会导致回滚)。
默认配置还提供了对 Vavr 的 Try
方法的支持,当它返回 'Failure' 时触发事务回滚。这使您能够使用 `Try` 处理函数式风格的错误,并在失败时自动回滚事务。有关 Vavr 的 `Try` 的更多信息,请参阅官方 Vavr 文档。以下是使用 Vavr 的 `Try` 和事务方法的一个示例:
-
Java
@Transactional
public Try<String> myTransactionalMethod() {
// If myDataAccessOperation throws an exception, it will be caught by the
// Try instance created with Try.of() and wrapped inside the Failure class
// which can be checked using the isFailure() method on the Try instance.
return Try.of(delegate::myDataAccessOperation);
}
从 Spring Framework 6.1 开始,`CompletableFuture`(以及一般的 `Future`)返回值也得到了特殊处理,如果此类句柄在原始方法返回时异常完成,将触发回滚。这适用于 @Async
方法,其中实际方法实现可能需要遵守 CompletableFuture
签名(在运行时通过 @Async
处理自动适配为对代理调用的实际异步句柄),优先在返回的句柄中暴露异常而不是重新抛出异常。
-
Java
@Transactional @Async
public CompletableFuture<String> myTransactionalMethod() {
try {
return CompletableFuture.completedFuture(delegate.myDataAccessOperation());
}
catch (DataAccessException ex) {
return CompletableFuture.failedFuture(ex);
}
}
从事务方法中抛出的 checked 异常在默认配置下不会导致回滚。您可以通过指定回滚规则来精确配置哪些 Exception
类型会标记事务回滚,包括 checked 异常。
回滚规则
回滚规则确定当抛出给定异常时是否应回滚事务,这些规则基于异常类型或异常模式。 回滚规则可以在 XML 中通过 当回滚规则使用异常类型定义时,该类型将用于匹配抛出异常的类型及其超类型,从而提供类型安全性并避免在使用模式时可能发生的任何意外匹配。例如,值 当回滚规则使用异常模式定义时,模式可以是异常类型(必须是
|
以下 XML 片段演示了如何通过 rollback-for
属性提供异常模式,从而为 checked 的、应用特定的 Exception
类型配置回滚。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
如果您不希望在抛出异常时回滚事务,也可以指定“不回滚”规则。以下示例指示 Spring Framework 的事务基础设施,即使遇到未处理的 InstrumentNotFoundException
,也要提交伴随的事务。
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
当 Spring Framework 的事务基础设施捕获到异常并查阅配置的回滚规则以确定是否将事务标记为回滚时,最强的匹配规则生效。因此,在以下配置的情况下,除了 InstrumentNotFoundException
之外的任何异常都会导致伴随事务的回滚。
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
</tx:attributes>
</tx:advice>
您也可以通过编程式方式指示需要回滚。尽管简单,但这个过程相当侵入性,并且将您的代码与 Spring Framework 的事务基础设施紧密耦合。以下示例展示了如何编程式指示需要回滚。
-
Java
-
Kotlin
public void resolvePosition() {
try {
// some business logic...
} catch (NoProductInStockException ex) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
fun resolvePosition() {
try {
// some business logic...
} catch (ex: NoProductInStockException) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
强烈建议您尽可能使用声明式方式进行回滚。如果确实需要,可以使用编程式回滚,但它的使用与实现简洁的基于 POJO 的架构相悖。