Spring 事務提交成功后執行額外邏輯

1. 場景與要解決的問題

  • 在業務代碼里,常見訴求是:只有當數據庫事務真正提交成功后,才去執行某些“后置動作”,例如:

    • 發送 MQ、推送消息、寫審計/埋點日志、刷新緩存、通知外部系統等。

  • 如果這些動作在事務提交前就執行,一旦事務最后回滾,就會出現數據與副作用不一致(例如:數據庫沒落庫,但 MQ 已發出)。

  • Spring 給出兩類工具來“跟隨事務走”:

    • TransactionSynchronization直接注冊事務回調,在 afterCommit() 等時點執行。

    • @TransactionalEventListener發布事件 + 事務階段監聽,在 AFTER_COMMIT 等階段觸發監聽方法。

2. TransactionSynchronization 使用方法

2.1 它是什么

  • 事務同步回調接口(Transaction Synchronization Callback Interface)。

  • 它能讓你在事務的關鍵節點(提交前、提交后、回滾后、完成后)掛接同步邏輯

  • 本質是 “鉤子/回調”,屬于 Spring 事務 SPI(Service Provider Interface)擴展點

2.2 使用方法

@Service
public class WithdrawService {@Transactional(rollbackFor = Exception.class)public void createWithdrawOrder(Long userId, BigDecimal amount) {// 1) 業務數據更新(示例)//   - 扣可用余額、加凍結余額、插入訂單等//   - 此處略…Long orderId = 123L; // 假設是插入訂單后拿到的IDBigDecimal income = amount;// 2) 綁定到“當前事務”的提交后回調TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {@Overridepublic void afterCommit() {try {// 3) 事務真正提交成功后才會執行到這里withdrawProducer.sendMessage(orderId);log.info("已發送提現MQ, orderId={}", orderId);} catch (Exception ex) {// 注意:此時事務已提交,失敗不會回滾主事務log.error("提交后發送MQ失敗, orderId={}", orderId, ex);// 可在此觸發重試/告警/記錄Outbox補償等}}});}
}

2.3 最佳實踐

  • 必須在活動事務中注冊:可用 TransactionSynchronizationManager.isSynchronizationActive() 檢查。

  • 不要在 afterCommit 里做重 IO/耗時操作,以免拉長請求尾延遲;建議再丟到自定義線程池執行。

  • 異常處理afterCommit 里異常不會回滾主事務(已提交),要自處置(告警/重試/Outbox)。

  • 事務傳播:在哪一層注冊,就跟隨那一層的事務。若內部有 REQUIRES_NEW 子事務,你在子事務里注冊的回調只跟隨子事務。

  • 多層回調:如果需要控制多個回調的順序,可讓回調實現 org.springframework.core.Ordered 接口,getOrder() 返回值越小優先級越高。


3. @TransactionalEventListener 使用方法

3.1 它是什么

  1. 發布-訂閱風格的事務階段監聽。業務方法里發布事件,監聽方法用 @TransactionalEventListener 聲明在指定事務階段運行(常用 AFTER_COMMIT)。

  2. 事件可以被多個監聽器消費;可配 @Async 在提交后異步執行。

3.2 使用方法(同步監聽模板)

// 1) 自定義事件(POJO 即可)
public record WithdrawOrderCreatedEvent(Long orderId, Long userId, BigDecimal amount) {}// 2) 事務中發布事件
@Service
public class WithdrawService {@Autowired private ApplicationEventPublisher publisher;@Transactional(rollbackFor = Exception.class)public void createWithdrawOrder(Long userId, BigDecimal amount) {// 業務入庫…(略)Long orderId = 123L;publisher.publishEvent(new WithdrawOrderCreatedEvent(orderId, userId, amount));}
}// 3) 監聽端:僅在“提交成功后”觸發
@Component
public class WithdrawEventListener {@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)public void onCreated(WithdrawOrderCreatedEvent evt) {try {withdrawProducer.sendMessage(evt.orderId());log.info("提交后發送MQ成功, orderId={}", evt.orderId());} catch (Exception ex) {log.error("提交后發送MQ失敗, orderId={}", evt.orderId(), ex);}}
}

3.3 提交后異步執行(可選)

@Configuration
@EnableAsync
public class AsyncCfg implements AsyncConfigurer {@Override public Executor getAsyncExecutor() {return Executors.newFixedThreadPool(8);}
}@Component
public class WithdrawAsyncListener {@Async@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)public void onCreated(WithdrawOrderCreatedEvent evt) {withdrawProducer.sendMessage(evt.orderId()); // 提交后異步發送}
}

4. 對比與選型

  • 一致性保障

    • 二者都能保證:只有事務提交成功后才執行(afterCommit / AFTER_COMMIT)。

  • 耦合與擴展

    • TransactionSynchronization:代碼直接注冊回調,與業務方法耦合,適合單一后置動作

    • @TransactionalEventListener發布-訂閱,天然解耦,一個事件可被多個監聽器消費,易擴展。

  • 異步能力

    • TransactionSynchronization:天生同步;可在回調內手動丟線程池異步。

    • @TransactionalEventListener:可直接疊加 @Async提交后異步執行。

  • 無事務時的行為

    • TransactionSynchronization必須存在活動事務,否則注冊失敗。

    • @TransactionalEventListener:默認無事務不觸發fallbackExecution = true 可強制執行(會失去“提交后”語義)。

  • 性能與代碼復雜度

    • TransactionSynchronization:路徑最短、開銷最小、代碼最少。

    • @TransactionalEventListener:有事件派發的輕微開銷,換來更好的解耦與可維護性。

  • 測試與團隊協作

    • TransactionSynchronization:更貼近底層鉤子,單一動作簡單直觀。

    • @TransactionalEventListener:語義清晰(業務事件),多人協作模塊解耦更友好,監聽可獨立單測。

  • 推薦選型(面向常見場景)

    • 只需一個消費方,追求超輕量 → 選 TransactionSynchronization.afterCommit()

    • 需要解耦/多個消費方/可異步 → 選 @TransactionalEventListener(phase = AFTER_COMMIT)

    • 需要強可靠(不能丟消息) → 在以上任一方案外,疊加 Outbox 模式(業務表 + 出站表同事務寫入,后臺可靠投遞 MQ/補償重試)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95699.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95699.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95699.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Clickhouse MCP@Mac+Cherry Studio部署與調試

一、需求背景 已經部署測試了Mysql、Drois的MCP Server,想進一步測試Clickhouse MCP的表現。 二、環境 1)操作系統 MacOS+Apple芯片 2)Clickhouse v25.7.6.21-stable、Clickhouse MCP 0.1.11 3)工具Cherry Studio 1.5.7、Docker Desktop 4.43.2(199162) 4)Python 3.1…

Java Serializable 接口:明明就一個空的接口嘛

對于 Java 的序列化,我之前一直停留在最淺層次的認知上——把那個要序列化的類實現 Serializbale 接口就可以了嘛。 我似乎不愿意做更深入的研究,因為會用就行了嘛。 但隨著時間的推移,見到 Serializbale 的次數越來越多,我便對它產生了濃厚的興趣。是時候花點時間研究研…

野火STM32Modbus主機讀取寄存器/線圈失敗(三)-嘗試將存貯事件的地方改成數組(非必要解決方案)(附源碼)

背景 盡管crc校驗正確了,也成功發送了EV_MASTER_EXECUTE事件,但是eMBMasterPoll( void )中總是接收的事件是EV_MASTER_FRAME_RECEIVED或者EV_MASTER_FRAME_SENT,一次都沒有執行EV_MASTER_EXECUTE。EV_MASTER_EXECUTE事件被別的事件給覆蓋了&…

微信小程序校園助手程序(源碼+文檔)

源碼題目:微信小程序校園助手程序(源碼文檔)?? 文末聯系獲取(含源碼、技術文檔)博主簡介:10年高級軟件工程師、JAVA技術指導員、Python講師、文章撰寫修改專家、Springboot高級,歡迎高校老師、…

59-python中的類和對象、構造方法

1. 認識一下對象 世間萬物皆是"對象" student_1{ "姓名":"小樸", "愛好":"唱、跳、主持" ......... }白紙填寫太落伍了 設計表格填寫先進一些些 終極目標是程序使用對象去組織數據程序中設計表格,我們稱為 設計類…

向成電子驚艷亮相2025物聯網展,攜工控主板等系列產品引領智造新風向

2025年8月27-29日,IOTE 2025 第二十四屆國際物聯網展深圳站在深圳國際會展中心(寶安)盛大啟幕!作為全球規模領先的物聯網盛會之一,本屆展會以“生態智能,物聯全球”為核心,匯聚超1000家全球頭部…

陣列信號處理之均勻面陣波束合成方向圖的繪制與特點解讀

陣列信號處理之均勻面陣波束合成方向圖的繪制與特點解讀 文章目錄前言一、方向圖函數二、方向圖繪制三、副瓣電平四、陣元個數對主瓣寬度的影響五、陣元間距對主瓣寬度的影響六、MATLAB源代碼總結前言 \;\;\;\;\;均勻面陣(Uniform Planar Array,UPA&…

算法在前端框架中的集成

引言 算法是前端開發中提升性能和用戶體驗的重要工具。隨著 Web 應用復雜性的增加,現代前端框架如 React、Vue 和 Angular 提供了強大的工具集,使得將算法與框架特性(如狀態管理、虛擬 DOM 和組件化)無縫集成成為可能。從排序算法…

網絡爬蟲是自動從互聯網上采集數據的程序

網絡爬蟲是自動從互聯網上采集數據的程序網絡爬蟲是自動從互聯網上采集數據的程序,Python憑借其豐富的庫生態系統和簡潔語法,成為了爬蟲開發的首選語言。本文將全面介紹如何使用Python構建高效、合規的網絡爬蟲。一、爬蟲基礎與工作原理 網絡爬蟲本質上是…

Qt Model/View/Delegate 架構詳解

Qt Model/View/Delegate 架構詳解 Qt的Model/View/Delegate架構是Qt框架中一個重要的設計模式,它實現了數據存儲、數據顯示和數據編輯的分離。這種架構不僅提高了代碼的可維護性和可重用性,還提供了極大的靈活性。 1. 架構概述 Model/View/Delegate架構將…

光譜相機在手機行業的應用

在手機行業,光譜相機技術通過提升拍照色彩表現和擴展健康監測等功能,正推動攝像頭產業鏈升級,并有望在AR/VR、生物醫療等領域實現更廣泛應用。以下為具體應用場景及技術突破的詳細說明:?一、光譜相機在手機行業的應用場景??拍照…

FASTMCP中的Resources和Templates

Resources 給 MCP 客戶端/LLM 讀取的數據端點(只讀、按 URI 索引、像“虛擬文件系統”或“HTTP GET”); Templates 可帶參數的資源路由(URI 里占位符 → 運行函數動態生成內容)。 快速要點 ? 用途:把文件…

OpenBMC之編譯加速篇

加快 OpenBMC 的編譯速度是一個非常重要的話題,因為完整的構建通常非常耗時(在高性能機器上也需要數十分鐘,普通電腦上可能長達數小時)。以下是從不同層面優化編譯速度的詳細策略,您可以根據自身情況組合使用。 一、核心方法:利用 BitBake 的緩存和共享機制(效果最顯著…

Kafka面試精講 Day 8:日志清理與數據保留策略

【Kafka面試精講 Day 8】日志清理與數據保留策略 在Kafka的高吞吐、持久化消息系統中,日志清理與數據保留策略是決定系統資源利用效率、數據可用性與合規性的關鍵機制。作為“Kafka面試精講”系列的第8天,本文聚焦于日志清理機制(Log Cleani…

基于Hadoop的網約車公司數據分析系統設計(代碼+數據庫+LW)

摘 要 本系統基于Hadoop平臺,旨在為網約車公司提供一個高效的數據分析解決方案。隨著網約車行業的快速發展,平臺上產生的數據量日益增加,傳統的數據處理方式已無法滿足需求。因此,設計了一種基于Hadoop的大規模數據處理和分析方…

Python反向迭代完全指南:從基礎到高性能系統設計

引言:反向迭代的核心價值在數據處理和算法實現中,反向迭代是解決復雜問題的關鍵技術。根據2024年Python開發者調查報告:85%的鏈表操作需要反向迭代78%的時間序列分析依賴反向處理92%的樹結構遍歷需要后序/逆序訪問65%的加密算法使用反向計算P…

ClickHouse使用Docker部署

OLTP和OLAP介紹基本業務量到達分庫分表量級,則離不開數據大屏、推薦系統、畫像系統等搭建,需要搭建以上系統,則離不開海量數據進行存儲-分析-統計。 而海量數據下 TB、PB級別數據存儲,靠Mysql進行存儲-分析-統計無疑是災難。所以就…

Python 算數運算練習題

計算數字特征值題目描述 編寫一個程序,接收用戶輸入的兩個整數 a 和 b(a > b > 0),計算并輸出以下結果:a 與 b 的和的平方a 除以 b 的商和余數a 與 b 的平均數(保留 2 位小數)示例請輸入整…

【物種分布模型】R語言物種氣候生態位動態量化與分布特征模擬——氣候生態位動態檢驗、質心轉移可視化、適生區預測等

R語言是一種廣泛用于統計分析和圖形表示的編程語言,強大之處在于可以進行多元數據統計分析,以及豐富的生態環境數據分析的方法,在生態學領域得到廣泛應用。本次教程將通過R語言多個程序包與GIS融合應用,提升物種氣候生態位動態量化…

【算法速成課2 | 題單】背包問題

專欄指路:《算法速成課》 前導: 動態規劃問題中最入門、也最多變的,當屬背包問題。 簡單來說,就是在有限的空間,(花費最小的代價)達成最大的收益。 本文會講一些常見的背包問題(可…