回滾宣告式事務

上一節概述瞭如何為應用程式中的類(通常是服務層類)宣告式地指定事務設定的基本知識。本節描述瞭如何在 XML 配置中以簡單、宣告式的方式控制事務回滾。有關使用 @Transactional 註解宣告式地控制回滾語義的詳細資訊,請參閱 @Transactional 設定

建議向 Spring 框架的事務基礎設施表明事務工作需要回滾的方式是,在當前在事務上下文中執行的程式碼中丟擲 Exception。Spring 框架的事務基礎設施程式碼會捕獲任何未處理的 Exception,因為它會冒泡到呼叫堆疊中,並確定是否將事務標記為回滾。

在其預設配置中,Spring 框架的事務基礎設施程式碼僅在執行時未檢查異常的情況下將事務標記為回滾。也就是說,當丟擲的異常是 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);
	}
}

在預設配置中,從事務方法丟擲的檢查異常不會導致回滾。您可以透過指定回滾規則來精確配置哪些 Exception 型別標記事務進行回滾,包括檢查異常。

回滾規則

回滾規則確定在丟擲給定異常時是否應回滾事務,並且這些規則基於異常型別或異常模式。

回滾規則可以在 XML 中透過 rollback-forno-rollback-for 屬性進行配置,這些屬性允許將規則定義為模式。使用 @Transactional 時,回滾規則可以透過 rollbackFor/noRollbackForrollbackForClassName/noRollbackForClassName 屬性進行配置,這些屬性分別允許根據異常型別或模式定義規則。

當使用異常型別定義回滾規則時——例如,透過 rollbackFor——該型別將用於與丟擲異常的型別進行匹配。具體來說,給定一個配置的異常型別 C,如果 T 等於 CC 的子類,則型別為 T 的丟擲異常將被視為與 C 匹配。這提供了型別安全性,並避免了在使用模式時可能發生的任何無意匹配。例如,值 jakarta.servlet.ServletException.class 將僅匹配型別為 jakarta.servlet.ServletException 及其子類的丟擲異常。

當使用異常模式定義回滾規則時,模式可以是異常型別的完全限定類名或完全限定類名的子字串(必須是 Throwable 的子類),目前不支援萬用字元。例如,值 "jakarta.servlet.ServletException""ServletException" 將匹配 jakarta.servlet.ServletException 及其子類。

您必須仔細考慮模式的特異性以及是否包含包資訊(這不是強制性的)。例如,"Exception" 將匹配幾乎所有內容,並且可能會隱藏其他規則。如果 "Exception" 旨在定義所有檢查異常的規則,那麼 "java.lang.Exception" 將是正確的。對於像 "BaseBusinessException" 這樣更獨特的異常名稱,可能不需要為異常模式使用完全限定類名。

此外,基於模式的回滾規則可能會導致對名稱相似的異常和巢狀類的無意匹配。這是因為如果丟擲異常的名稱包含為回滾規則配置的異常模式,則認為丟擲的異常與給定基於模式的回滾規則匹配。例如,給定一個配置為匹配 "com.example.CustomException" 的規則,該規則將匹配名為 com.example.CustomExceptionV2(與 CustomException 在同一包中但帶有附加字尾的異常)或名為 com.example.CustomException$AnotherException(在 CustomException 中宣告為巢狀類的異常)的異常。

以下 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>

如果您不希望在丟擲異常時回滾事務,您還可以指定“不回滾”規則。以下示例告訴 Spring 框架的事務基礎設施即使在出現未處理的 InstrumentNotFoundException 時也要提交附帶的事務

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

當 Spring 框架的事務基礎設施捕獲到異常並查閱配置的回滾規則以確定是否將事務標記為回滾時,最強的匹配規則獲勝。因此,在以下配置中,除了 InstrumentNotFoundException 之外的任何異常都會導致附帶事務的回滾

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

您還可以以程式設計方式指示所需的滾動回。雖然簡單,但此過程具有侵入性,並使您的程式碼與 Spring 框架的事務基礎設施緊密耦合。以下示例顯示瞭如何以程式設計方式指示所需的滾動回

  • 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 的純淨架構相悖。

© . This site is unofficial and not affiliated with VMware.