回滚声明式事务
上一节概述了如何在应用程序中以声明方式为类(通常是服务层类)指定事务设置的基本知识。本节介绍如何以简单、声明的方式在 XML 配置中控制事务回滚。
向 Spring 框架的事务基础结构指示要回滚事务工作的推荐方法是从当前在事务上下文中执行的代码中抛出Exception
。Spring 框架的事务基础结构代码会捕获任何未处理的Exception
(当它向上冒泡调用堆栈时),并确定是否将事务标记为回滚。
在默认配置中,Spring 框架的事务基础结构代码仅在运行时、未检查的异常情况下将事务标记为回滚。也就是说,当抛出的异常是RuntimeException
的实例或子类时。(Error
实例在默认情况下也会导致回滚)。
默认配置还支持 Vavr 的Try
方法,当它返回“失败”时触发事务回滚。这允许您使用 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);
}
}
在默认配置中,从事务方法抛出的已检查异常不会导致回滚。您可以通过指定*回滚规则*来配置哪些Exception
类型将事务标记为回滚,包括已检查异常。
回滚规则
回滚规则确定在抛出给定异常时是否应回滚事务,这些规则基于异常类型或异常模式。 可以通过 当使用异常类型定义回滚规则时,该类型将用于与抛出异常的类型及其超类型进行匹配,从而提供类型安全并避免使用模式时可能发生的任何意外匹配。例如, 当使用异常模式定义回滚规则时,该模式可以是异常类型的完全限定类名或完全限定类名的子字符串(必须是
|
以下 XML 代码片段演示了如何通过rollback-for
属性提供异常模式来配置已检查的、特定于应用程序的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>
如果您不希望在抛出异常时回滚事务,也可以指定“no rollback”规则。以下示例告诉 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 的架构相违背。