在 Spring 中使用事務處理非同步執行:一個常見的陷阱以及如何解決它
在現代 Spring 應用程式中,將非同步執行與事務行為結合是很常見的。但是,使用 @Async 和 @Transactional(propagation = Propagation.REQUIRES_NEW) 註解方法可能會導致意外行為,因為 Spring 管理非同步任務和交易。
在本文中,我們將詳細探討該問題並示範正確處理非同步執行和事務管理的解決方案。
問題:@Async 和 @Transactional(propagation = Propagation.REQUIRES_NEW)
考慮以下程式碼片段:
@Async @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveSomething() { // save-point one // save-point two }
乍一看,似乎一切都如預期進行。但是,此配置存在一些關鍵問題,可能會導致意外行為。
幕後發生了什麼事?
- @Async 註:
@Async 註解告訴 Spring 在單獨的執行緒中非同步執行該方法。這意味著該方法不會在呼叫它的原始執行緒中運行,而是會被卸載到執行緒池中的另一個執行緒。
Spring 使用代理來管理非同步方法。當您呼叫使用 @Async 註解的方法時,Spring 將執行委託給在不同執行緒中執行該方法的內部 Executor。
- @Transactional(propagation = Propagation.REQUIRES_NEW) 註:
@Transactional(propagation = Propagation.REQUIRES_NEW) 註解可確保為該方法啟動一個新事務,無論任何現有事務如何。它掛起呼叫執行緒中的任何活動事務並為該方法開始一個新事務。
Spring 中的事務管理通常是執行緒綁定的,這表示事務上下文與當前執行緒綁定。
衝突
出現這個問題是因為@Async在不同的執行緒中執行該方法,而Spring的事務管理依賴執行緒來綁定事務。當該方法非同步執行時,來自呼叫線程的事務上下文不會傳播到新線程,這會導致以下問題:
- @Transactional 註解不會在非同步執行緒中建立新事務,任何事務行為(如回滾、提交等)都不會被正確處理。
- REQUIRES_NEW 傳播設定將不適用,因為非同步方法在原始事務上下文之外運作。
解決方案:解耦異步執行和事務
為了解決這個問題,您可以透過在單獨的服務方法中處理事務來將非同步執行與事務邏輯解耦。具體方法如下:
第 1 步:為事務邏輯建立新的同步服務
建立一個處理事務邏輯的新服務。此方法將同步執行(不使用@Async)以確保事務管理能如預期運作。第2步:非同步呼叫同步方法
然後,您可以使用 @Async 非同步呼叫同步事務方法。這確保了在主執行緒中正確處理事務邏輯,並且仍然保持異步行為。
重構後的程式碼如下圖所示:
@Async @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveSomething() { // save-point one // save-point two }
它是如何運作的?
重構後的解決方案中,透過使用 @Async 註解 saveSomethingAsync() 方法來實現非同步執行。這意味著當呼叫 saveSomethingAsync() 時,它將在由 Spring 的非同步任務執行器管理的單獨執行緒中執行。在不同的執行緒中運行它允許主執行緒繼續執行,而無需等待 saveSomethingAsync() 完成。這種方法對於您想要卸載長時間運行的任務、提高回應能力或同時處理獨立操作的場景很有用。
對於事務行為,TransactionalService 中的 saveSomething() 方法以 @Transactional(propagation = Propagation.REQUIRES_NEW) 進行註解。這確保每次呼叫 saveSomething() 都會建立一個獨立於呼叫方法中任何現有事務的新事務。 REQUIRES_NEW 傳播啟動一項新事務並暫停任何現有事務,從而允許 saveSomething() 在隔離的事務上下文中進行操作。這意味著即使原始呼叫方法有事務,saveSomething() 也將在其自己的單獨事務中工作,從而僅針對此操作啟用受控提交和回滾。
透過將非同步執行與事務邏輯解耦,我們確保事務管理能如預期運作。在此設定中,事務上下文在 saveSomething() 方法中保持正確處理,而 saveSomethingAsync() 方法繼續在單獨的執行緒中執行。這種關注點分離可以兼具非同步處理和可靠事務管理的優點,即使在並發處理時也能實現獨立且安全的資料操作。
何時使用此方法?
當交易隔離至關重要時:如果您需要確保某些操作在單獨的事務中執行(即 REQUIRES_NEW),則此方法效果很好。
非同步操作:如果您有長時間運行的獨立任務,需要非同步執行,但也需要自己的交易邊界。
替代方案:使用訊息佇列實作完全解耦
如果您需要更進階的解耦或希望處理重試、錯誤處理和長時間運行的流程,請考慮將任務卸載到 Kafka 或 RabbitMQ 等訊息佇列。透過使用訊息佇列,可以確保每個任務在自己的上下文中運行,並且可以獨立管理交易。
以上是在 Spring 中使用事務處理非同步執行:一個常見的陷阱以及如何解決它的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

在使用IntelliJIDEAUltimate版本啟動Spring...

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

Redis緩存方案如何實現產品排行榜列表的需求?在開發過程中,我們常常需要處理排行榜的需求,例如展示一個�...

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...
