对于最新的稳定版本,请使用 Spring Framework 6.2.0spring-doc.cadn.net.cn

回滚声明式事务

上一节概述了如何为 类(通常是服务层类)在您的应用程序中以声明方式。本节 描述如何在简单的声明式 fashion 的 XML 配置。有关以声明方式控制回滚语义的详细信息 使用@Transactional注解,请参阅@Transactional设置.spring-doc.cadn.net.cn

向 Spring 框架的事务基础结构指示的推荐方法 事务的工作要回滚是抛出一个Exceptionfrom code 中, 当前正在事务的上下文中执行。Spring 框架的 事务基础设施代码捕获任何未处理的Exception当它冒泡时 调用堆栈,并确定是否将事务标记为回滚。spring-doc.cadn.net.cn

在其默认配置中, Spring 框架的事务基础结构代码 仅在运行时未检查异常的情况下将事务标记为回滚。 也就是说,当引发的异常是RuntimeException. (Error实例也会导致回滚)。spring-doc.cadn.net.cn

从 Spring Framework 5.2 开始,默认配置还提供了对 Vavr 的Try方法在返回 'Failure' 时触发事务回滚。 这允许您使用 Try 处理函数式错误并拥有事务 发生故障时自动回滚。有关 Vavr 的 Try 的更多信息, 请参阅官方 Vavr 文档。 以下是如何将 Vavr 的 Try 与事务方法结合使用的示例:spring-doc.cadn.net.cn

@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在运行时处理)、 更喜欢在返回的句柄中公开,而不是重新引发异常:spring-doc.cadn.net.cn

@Transactional @Async
public CompletableFuture<String> myTransactionalMethod() {
	try {
		return CompletableFuture.completedFuture(delegate.myDataAccessOperation());
	}
	catch (DataAccessException ex) {
		return CompletableFuture.failedFuture(ex);
	}
}

从事务方法引发的已检查异常不会导致回滚 在默认配置中。您可以准确配置哪些Exception类型标记 transaction 进行回滚,包括通过指定 rollback 规则检查的异常。spring-doc.cadn.net.cn

回滚规则

回滚规则确定在给定异常 thrown,并且规则基于异常类型或异常模式。spring-doc.cadn.net.cn

回滚规则可以通过rollback-forno-rollback-for属性,允许将规则定义为模式。使用@Transactional,回滚规则可能会 通过rollbackFor/noRollbackForrollbackForClassName/noRollbackForClassName属性,这些属性允许规则为 分别根据异常类型或模式定义。spring-doc.cadn.net.cn

当使用异常类型定义回滚规则时,将使用该类型进行匹配 针对引发的异常的类型及其超类型,提供类型安全性和 避免使用模式时可能发生的任何意外匹配。例如, 的值jakarta.servlet.ServletException.class将仅匹配 类型jakarta.servlet.ServletException及其子类。spring-doc.cadn.net.cn

当使用异常模式定义回滚规则时,该模式可以是完全的 异常类型的限定类名或完全限定类名的子字符串 (必须是Throwable),目前不支持通配符。为 example,则值为"jakarta.servlet.ServletException""ServletException"将 火柴jakarta.servlet.ServletException及其子类。spring-doc.cadn.net.cn

您必须仔细考虑模式的具体程度以及是否包含 package 信息(这不是强制性的)。例如"Exception"将几乎匹配 任何内容,并且可能会隐藏其他规则。"java.lang.Exception"如果"Exception"用于定义所有已检查异常的规则。具有更独特的 异常名称(如"BaseBusinessException"可能不需要使用 异常模式的完全限定类名。spring-doc.cadn.net.cn

此外,基于模式的回滚规则可能会导致 名称相似的 Exceptions 和 Nested 类。这是因为抛出的 exception 被视为与给定的基于模式的回滚规则匹配,如果名称 的 Thrown 异常 包含为 rollback 规则配置的异常模式。 例如,给定一个配置为匹配"com.example.CustomException"那 rule 将与名为com.example.CustomExceptionV2(例外 在与CustomException但带有额外的后缀)或例外 叫com.example.CustomException$AnotherException(声明为嵌套 类CustomException).spring-doc.cadn.net.cn

以下 XML 代码段演示了如何为选中的 特定于应用程序Exceptiontype 通过rollback-for属性:spring-doc.cadn.net.cn

<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 框架的 transaction 基础设施来提交伴随的事务,即使面对 未处理InstrumentNotFoundException:spring-doc.cadn.net.cn

<tx:advice id="txAdvice">
	<tx:attributes>
		<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
		<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

当 Spring 框架的事务基础结构捕获到异常并咨询 配置的 rollback 规则,用于确定是否将事务标记为 rollback, 最强的匹配规则胜出。因此,在以下配置的情况下,任何 exception 以外的InstrumentNotFoundException导致 随行交易:spring-doc.cadn.net.cn

<tx:advice id="txAdvice">
	<tx:attributes>
		<tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
	</tx:attributes>
</tx:advice>

您还可以以编程方式指示所需的回滚。虽然简单,但这个过程 非常具有侵入性,并将您的代码与 Spring Framework 的事务紧密耦合 基础设施。以下示例演示如何以编程方式指示所需的 反转:spring-doc.cadn.net.cn

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 的干净架构背道而驰。spring-doc.cadn.net.cn