回滾宣告式交易
前一節概述了如何在應用程式中以宣告方式為類別(通常是服務層類別)指定交易設定的基本知識。本節介紹如何在 XML 配置中以簡單、宣告式的方式控制交易的回滾。如需使用 @Transactional
註解以宣告方式控制回滾語意的詳細資訊,請參閱 @Transactional
設定。
向 Spring Framework 的交易基礎架構表明交易工作需要回滾的建議方式,是從目前在交易上下文中執行的程式碼中擲回 Exception
。Spring Framework 的交易基礎架構程式碼會捕捉任何未處理的 Exception
,因為它會沿著呼叫堆疊向上冒泡,並判斷是否將交易標記為回滾。
在其預設配置中,Spring Framework 的交易基礎架構程式碼僅在執行階段、未檢查例外的情況下將交易標記為回滾。也就是說,當擲回的例外是 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
處理自動調整為對 Proxy 的呼叫的實際非同步句柄),優先在傳回的句柄中公開,而不是重新擲回例外
-
Java
@Transactional @Async
public CompletableFuture<String> myTransactionalMethod() {
try {
return CompletableFuture.completedFuture(delegate.myDataAccessOperation());
}
catch (DataAccessException ex) {
return CompletableFuture.failedFuture(ex);
}
}
在預設配置中,從交易方法擲回的已檢查例外不會導致回滾。您可以透過指定回滾規則來配置確切的 Exception
類型,以將交易標記為回滾,包括已檢查例外。
回滾規則
回滾規則決定在擲回給定例外時是否應回滾交易,規則基於例外類型或例外模式。 回滾規則可以在 XML 中透過 當使用例外類型定義回滾規則時,該類型將用於比對擲回的例外類型及其父類型,從而提供類型安全,並避免在使用模式時可能發生的任何意外比對。例如, 當使用例外模式定義回滾規則時,該模式可以是例外類型的完整類別名稱,也可以是例外類型完整類別名稱的子字串(必須是
|
以下 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 的架構背道而馳。