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

回滚声明式事务操作

上一节概述了如何在应用程序中对类(通常是服务层类)以声明方式指定事务设置的基本方法。本节将介绍如何在XML配置中以简单的方式声明式地控制事务的回滚。有关使用<code>0</code>注解以声明方式控制回滚语义的详细信息,请参见 1</code> 设置spring-doc.cadn.net.cn

指示Spring框架的事务基础设施在事务的处理过程中需要回滚的推荐方法是,从当前正在事务上下文中执行的代码中抛出一个Exception。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文档spring-doc.cadn.net.cn

以下是一个在事务性方法中使用 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);
}

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

回滚规则

回滚规则用于确定当抛出指定异常时事务是否应被回滚,这些规则基于异常类型或异常模式。spring-doc.cadn.net.cn

回滚规则可以通过 rollback-forno-rollback-for 属性在 XML 中进行配置,该配置允许将规则定义为模式。使用 @Transactional 时,可通过 rollbackFor/noRollbackForrollbackForClassName/noRollbackForClassName 属性配置回滚规则,这些属性分别支持基于异常类型或模式定义规则。spring-doc.cadn.net.cn

当回滚规则通过异常类型定义时,该类型将用于匹配抛出的异常及其超类型,从而提供类型安全并避免使用模式匹配时可能发生的意外匹配。例如,jakarta.servlet.ServletException.class值仅会匹配jakarta.servlet.ServletException类型及其子类抛出的异常。spring-doc.cadn.net.cn

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

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

此外,基于模式的回滚规则可能导致对名称相似的异常和嵌套类产生意外匹配。这是因为当抛出的异常名称包含为回滚规则配置的异常模式时,该异常就会被视为匹配给定的基于模式的回滚规则。例如,给定配置为匹配"com.example.CustomException"的规则,该规则将匹配名为com.example.CustomExceptionV2的异常(该异常与CustomException位于同一包但带有额外后缀)或名为com.example.CustomException$AnotherException的异常(该异常在CustomException中被声明为嵌套类)。spring-doc.cadn.net.cn

以下XML片段演示了如何通过使用rollback-for属性提供异常模式来为已检查的、特定于应用程序的Exception类型配置回滚: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>

如果您不希望在抛出异常时回滚事务,还可以指定“不回滚”规则。下面的示例告诉Spring框架的事务基础设施,在遇到未处理的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框架的事务基础设施捕获异常并查阅配置的回滚规则以确定是否将事务标记为回滚时,最强匹配规则将获胜。因此,在以下配置的情况下,除了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 框架的事务基础设施紧密耦合。下面的例子展示了如何以编程方式指示需要回滚: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