事務傳播行為詳解

一、事務傳播行為的基本概念

事務傳播行為是Spring 框架中事務管理的核心概念,用于定義當一個事務方法被另一個事務方法調用時,事務應如何傳播。通俗地說,它解決了 “多個事務方法嵌套調用時,新方法是加入現有事務還是創建新事務” 的問題。

事務傳播行為詳解

在 Spring 中,事務傳播行為通過@Transactional注解的propagation屬性設置,或在TransactionDefinition接口中定義。

二、Spring 事務傳播行為的類型及詳解

Spring 定義了 7 種事務傳播行為,以下是詳細說明:

傳播行為類型英文名稱核心定義典型應用場景

PROPAGATION_REQUIRED

(propagation_required)

REQUIRED(默認)若當前存在事務,則加入該事務;若不存在,則創建新事務核心業務邏輯(如訂單創建、支付流程),確保操作在統一事務中。

PROPAGATION_REQUIRES_NEW

(propagation_requires_new)

REQUIRES_NEW無論當前是否存在事務,都創建新事務,原事務會被掛起。異步任務、日志記錄(不希望主事務失敗影響子任務),或需要獨立回滾的操作。

PROPAGATION_NESTED

(propagation_nested)

NESTED若當前存在事務,則創建嵌套事務(通過數據庫 Savepoint 實現);若不存在,則創建新事務。MySQL 等支持 Savepoint 的數據庫中,需要部分回滾的場景(如訂單部分退款)。

PROPAGATION_SUPPORTS

(propagation_supports)

SUPPORTS若當前存在事務,則加入事務;若不存在,則以非事務方式執行。只讀查詢方法,可復用外層事務,也可獨立執行。

PROPAGATION_NOT_SUPPORTED

(propagation_not_supported)

NOT_SUPPORTED以非事務方式執行,若當前存在事務,則掛起該事務。明確不需要事務的操作(如緩存更新),避免事務開銷。

PROPAGATION_NEVER

(propagation_never)

NEVER強制以非事務方式執行,若當前存在事務,則拋出異常。確保方法絕對不運行在事務中(如只讀緩存服務)。

PROPAGATION_MANDATORY

(propagation_mandatory)

MANDATORY強制要求當前存在事務,否則拋出異常。子方法必須依賴外層事務(如財務系統中的分賬操作)。

三、(@Transactional注解的propagation屬性)的生效條件觸發時機

Spring事務傳播行為(@Transactional注解的propagation屬性)的生效條件和觸發時機需要結合以下幾點來理解:

1. 注解何時起作用?

Spring事務傳播行為的注解(如@Transactional(propagation = Propagation.REQUIRED))會在以下場景中生效:

  • 方法被調用時:當一個事務方法(帶有@Transactional注解)被另一個方法調用時,事務傳播行為會根據當前事務上下文動態決定如何處理事務。
  • 代理機制觸發:Spring通過動態代理(JDK動態代理或CGLIB代理)管理事務。只有當方法是通過代理對象調用時,事務傳播行為才會生效。

2.事務傳播行為的觸發流程

事務傳播行為的觸發流程可以簡化為以下步驟:

方法調用時檢查事務上下文:Spring會檢查當前是否存在事務(例如,調用方是否已經開啟事務)。
根據傳播行為決定事務處理方式:

  • 新建事務(如REQUIRES_NEW):掛起當前事務(如果有),開啟新事務。
  • 加入事務(如REQUIRED):直接使用當前事務。
  • 強制要求/禁止事務(如MANDATORY/NEVER):根據規則拋出異常或掛起事務。

執行方法邏輯:在確定事務上下文后,執行方法體內的業務邏輯。
事務提交或回滾:根據方法執行結果和傳播行為規則提交或回滾事務。

3.示例代碼

REQUIRED 傳播行為的核心原則 “如果存在事務則加入,不存在則創建新事務” 是針對每個被調用的方法而言的。具體邏輯如下:

⑴. 核心判斷時機

當一個被 @Transactional(propagation = Propagation.REQUIRED) 注解的方法被調用時,Spring 會檢查當前調用環境是否存在活躍事務:

  • 如果存在事務:方法會加入該事務,共享同一事務上下文。
  • 如果不存在事務:方法會創建一個新事務。

⑵. 示例說明

場景一:調用鏈中已有事務

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事務已創建methodB(); // 調用 methodB
}@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {// methodB 加入 methodA 的事務
}
  • 分析methodB?被調用時,由于調用鏈中已存在?methodA?創建的事務,methodB?直接加入該事務,兩者共享同一事務邊界。

場景二:調用鏈中無事務

public void methodA() {// 無事務methodB(); // 調用 methodB
}@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {// methodB 創建新事務
}
  • 分析methodB?被調用時,由于調用鏈中不存在事務,methodB?會創建一個新事務。

⑶.?關鍵點

  • 與方法層級無關:無論方法是被直接調用還是嵌套在多層調用鏈中,判斷邏輯始終是當前調用環境是否存在事務
  • 事務上下文由 Spring 維護Spring 通過?TransactionSynchronizationManager?管理事務上下文,確保同一線程中共享事務狀態。
  • 自調用問題:若方法在同一個類中被自調用(如?this.methodB()),@Transactional?注解會失效,因為 Spring 的 AOP 代理機制只攔截外部調用。

"在同一事務中" 的含義


四、核心傳播行為的典型場景與示例

1.propagation_required(默認行為)

這是最常用的傳播行為。如果當前存在事務,則加入該事務;如果不存在,則創建一個新事務。

應用場景:核心業務邏輯,確保多個操作在同一事務中。

示例:創建訂單并扣減庫存

@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate InventoryService inventoryService;@Transactional(propagation = Propagation.REQUIRED)public Order createOrder(Order order) {// 保存訂單Order savedOrder = orderRepository.save(order);// 扣減庫存 (假設該方法也使用 REQUIRED 傳播行為)inventoryService.reduceStock(order.getProductId(), order.getQuantity());return savedOrder;}
}

在這個例子中,如果?createOrder?方法被一個事務調用,reduceStock?方法會加入這個事務;如果沒有事務,這兩個操作會在一個新事務中執行。

2.propagation_requires_new

無論當前是否存在事務,都創建一個新事務,原事務會被掛起。

應用場景:異步任務、日志記錄,不希望主事務失敗影響子任務。

示例:訂單支付與日志記錄

@Service
public class PaymentService {@Autowiredprivate LogService logService;@Transactional(propagation = Propagation.REQUIRED)public void processPayment(Payment payment) {// 處理支付try {// 支付邏輯...// 記錄支付日志 (使用 REQUIRES_NEW 確保即使主事務回滾,日志也會記錄)logService.recordPaymentLog(payment);// 可能拋出異常的操作if (payment.getAmount() > 10000) {throw new PaymentException("金額過大需要審核");}} catch (Exception e) {// 異常處理}}
}@Service
public class LogService {@Transactional(propagation = Propagation.REQUIRES_NEW)public void recordPaymentLog(Payment payment) {// 記錄日志邏輯}
}

在這個例子中,即使?processPayment?方法因異常回滾,recordPaymentLog?方法創建的日志記錄也會被持久化,因為它在獨立的事務中執行。

3.propagation_nested

如果當前存在事務,則創建一個嵌套事務(通過數據庫 Savepoint 實現);如果不存在,則創建一個新事務。

應用場景:需要部分回滾的場景,如訂單部分退款。

示例:訂單部分退款

@Service
public class RefundService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate PaymentRepository paymentRepository;@Transactional(propagation = Propagation.REQUIRED)public void processPartialRefund(Long orderId, BigDecimal refundAmount) {Order order = orderRepository.findById(orderId).orElseThrow();// 創建嵌套事務處理退款try {refundPayment(order.getPaymentId(), refundAmount);// 更新訂單狀態order.setStatus(OrderStatus.PARTIALLY_REFUNDED);orderRepository.save(order);} catch (RefundException e) {// 退款失敗,但訂單狀態更新不會受影響// 嵌套事務的回滾不會影響外層事務order.setStatus(OrderStatus.REFUND_FAILED);orderRepository.save(order);}}@Transactional(propagation = Propagation.NESTED)public void refundPayment(Long paymentId, BigDecimal amount) {// 退款邏輯if (amount > 1000) {throw new RefundException("退款金額超過限制");}// 執行退款...}
}

在這個例子中,如果?refundPayment?方法拋出異常,只會回滾嵌套事務中的操作,而外層事務中的訂單狀態更新仍然會提交。

4.propagation_supports

如果當前存在事務,則加入事務;如果不存在,則以非事務方式執行。

應用場景:只讀查詢方法,可以復用外層事務,也可以獨立執行。

示例:查詢訂單詳情

@Service
public class OrderQueryService {@Autowiredprivate OrderRepository orderRepository;@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)public Order getOrderDetails(Long orderId) {// 查詢訂單詳情return orderRepository.findById(orderId).orElseThrow();}
}

在這個例子中,如果?getOrderDetails?方法在事務中被調用,它會加入該事務;如果不在事務中,它會以非事務方式執行。這對于只讀操作很有用,可以減少事務開銷。

5.propagation_not_supported

以非事務方式執行,如果當前存在事務,則掛起該事務。

應用場景:明確不需要事務的操作,如緩存更新。

示例:更新緩存

@Service
public class CacheService {@Transactional(propagation = Propagation.NOT_SUPPORTED)public void updateCache(String key, Object value) {// 更新緩存邏輯// 這里不需要事務,因為緩存操作通常不需要回滾}
}

在這個例子中,如果?updateCache?方法在事務中被調用,當前事務會被掛起,方法執行完畢后再恢復。

6.propagation_never

強制以非事務方式執行,如果當前存在事務,則拋出異常。

應用場景:確保方法絕對不運行在事務中,如只讀緩存服務。

示例:從緩存獲取數據

@Service
public class CacheQueryService {@Transactional(propagation = Propagation.NEVER)public Object getFromCache(String key) {// 從緩存獲取數據// 確保此方法不會在事務中執行return cache.get(key);}
}

在這個例子中,如果?getFromCache?方法在事務中被調用,會拋出異常,確保緩存操作不會在事務上下文中執行。

7.propagation_mandatory

強制要求當前存在事務,否則拋出異常。

應用場景:子方法必須依賴外層事務,如財務系統中的分賬操作。

示例:財務分賬

@Service
public class AccountingService {@Transactional(propagation = Propagation.MANDATORY)public void distributeFunds(Payment payment) {// 分賬邏輯// 必須在事務中執行,確保數據一致性}
}@Service
public class PaymentProcessingService {@Autowiredprivate AccountingService accountingService;@Transactional(propagation = Propagation.REQUIRED)public void processPayment(Payment payment) {// 處理支付// ...// 分賬 (依賴外層事務)accountingService.distributeFunds(payment);}
}

在這個例子中,distributeFunds?方法必須在事務中調用,否則會拋出異常。這確保了分賬操作不會在沒有事務保護的情況下執行。

五、事務傳播行為的底層實現原理

  1. 數據庫事務與 Spring 事務的映射

    • Spring 通過PlatformTransactionManager抽象層管理事務,不同數據庫(如 MySQL、Oracle)的事務機制會影響傳播行為的實現。
    • 例如:PROPAGATION_NESTED依賴數據庫的SAVEPOINT機制,MySQL InnoDB 引擎支持,而 MyISAM 不支持。
  2. 事務掛起與恢復

    • 當使用REQUIRES_NEWNESTED時,Spring 會將當前事務狀態(如連接、隔離級別)保存到TransactionStatus對象中,新事務完成后恢復原事務。

六、實戰最佳實踐與注意事項

  1. 優先使用默認傳播行為(REQUIRED)

    • 核心業務邏輯通常需要事務一致性,默認值可避免遺漏配置。
  2. REQUIRES_NEW 的性能開銷

    • 新事務會導致數據庫連接切換和事務日志開銷,非必要場景避免濫用。
  3. NESTED 的數據庫兼容性

    • 若系統需跨數據庫部署,謹慎使用NESTED,可考慮用REQUIRES_NEW替代。
  4. 事務邊界控制

    • 避免在循環中調用REQUIRES_NEW方法(如批量插入),可通過@Transactional包裹整個循環以減少事務開銷。
  5. 異常處理與事務回滾

    • 傳播行為會影響異常傳播,例如REQUIRES_NEW的子事務異常不會影響外層事務,需顯式處理異常或配置rollbackFor

七、總結

事務傳播行為是 Spring 事務管理的核心機制,合理選擇傳播行為可解決以下問題:

  • 多個服務方法間的事務邊界劃分
  • 核心業務與輔助操作的事務隔離
  • 復雜業務流程中的部分回滾需求

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

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

相關文章

Java八股文——Spring「SpringMVC 篇」

MVC分層介紹一下 面試官您好,MVC是一種非常經典、影響深遠的軟件設計模式,它的全稱是Model-View-Controller。在我看來,它的核心目標就是解決早期Web開發中,業務邏輯、數據和界面顯示高度耦合的問題,從而實現“各司其…

FreeSWITCH mod_curl 和 mod_xml_rpc 測試

編輯 /usr/local/freeswitch/conf/autoload_configs/xml_rpc.conf.xml <configuration name"xml_rpc.conf" description"XML RPC"> <settings> <param name"http-port" value"8889"/> <param name&quo…

實時監控、秒級決策:鏡舟科技如何重塑融資融券業務數據處理模式

融資融券業務作為證券市場的重要組成部分&#xff0c;已成為金融機構核心業務增長點和利潤來源。截至 2023 年底&#xff0c;我國融資融券余額已突破 1.8 萬億元&#xff0c;業務量呈現爆發式增長。然而&#xff0c;在業務高速發展的同時&#xff0c;金融機構面臨著數據處理效率…

Linux與量子計算:面向未來的架構演進

Linux與量子計算&#xff1a;面向未來的架構演進 當經典計算遇上量子革命 引言&#xff1a;量子計算時代的黎明 量子計算正從理論走向工程實踐&#xff0c;Linux作為現代計算的基石&#xff0c;正在量子革命中扮演關鍵角色。據IBM預測&#xff0c;到2027年&#xff0c;量子優勢…

Java中wait()為何必須同步調用?

在 Java 中&#xff0c;wait() 方法必須在 synchronized 方法或代碼塊中調用&#xff0c;主要原因如下&#xff1a; 1. 監視器鎖&#xff08;Monitor&#xff09;機制 依賴對象鎖&#xff1a;wait() 方法需要操作對象的監視器鎖&#xff08;Monitor&#xff09;&#xff0c;調…

前端面試專欄-基礎篇:4. 頁面渲染流程與性能優化

頁面渲染流程與性能優化詳解&#xff08;完整版&#xff09; 一、現代瀏覽器渲染流程&#xff08;詳細說明&#xff09; 1. 構建DOM樹 瀏覽器接收到HTML文檔后&#xff0c;會逐步解析并構建DOM&#xff08;Document Object Model&#xff09;樹。具體過程如下&#xff1a; (…

漲薪技術|Docker端口映射與容器互聯技術

前面的推文我們學了Docker操作的常用命令,今天開始給大家分享Docker端口映射與容器互聯,歡迎關注。Docker不管是程序員,架構師或者測試工程師都必須要掌握的一門主流技術。 Docker除了通過網絡訪問外,還提供了兩個很方便的功能來滿足服務訪問的基本需求,一個是允許映射容…

Roboguide工作站機器人重新安裝軟件包

1、點擊菜單欄“機器人-屬性”&#xff1b; 2、點擊“重新生成”&#xff1b; 3、點擊“確定”&#xff1b; 4、點擊“6&#xff1a;機器人選項” 5、在搜索框搜索軟件包&#xff0c;或在軟件包列表選擇&#xff0c;勾選軟件包后點擊“下一步”&#xff1b; 6、點擊“完成”&am…

預訓練CNN網絡的遷移學習(MATLAB例)

從基于大型數據集訓練的神經網絡中提取層&#xff0c;并基于新數據集進行微調。本例使用ImageNet中的子集進行微調。 This example retrains a SqueezeNet neural network using transfer learning. This network has been trained on over a million images, and can classif…

kali系統 windows Linux靶機入侵演練

Kali系統與Windows/Linux靶機入侵演練簡介 演練概述 Kali Linux是一款專為滲透測試和網絡安全評估設計的操作系統,常被安全專業人員用于合法的安全測試。入侵演練是網絡安全訓練的重要組成部分,旨在幫助安全人員了解攻擊手法并提升防御能力。 基本組件 1. **攻擊機**:通常…

手搓transformer

思路是這樣子的&#xff1a;從手搓代碼的角度去學習transformer&#xff0c;代碼會一個一個模塊地從頭到尾添加&#xff0c;以便學習者跟著敲&#xff0c;到最后再手搓一個基于tansformer的機器翻譯實戰項目。 transformer整體架構 一、輸入部分 詞向量 import torch import t…

網絡層協議:IP

目錄 1、概念 2、關鍵組成部分 2.1 IP地址 2.1.1 概念 2.1.2 主要版本 2.1.3 IP地址分類 2.2 IP數據報&#xff08;IP協議傳輸的基本數據單元&#xff09; 3、工作原理 3.1 路由 3.2 分片與重組 4、相關協議 1、概念 目的&#xff1a;負責在復雜的網絡環境中將數據…

Fastadmin報錯Unknown column ‘xxx.deletetime‘ in ‘where clause

報錯原因 在開啟軟刪除后&#xff0c;設置了表別名&#xff0c;軟刪除字段依舊使用原表名。 解決方法 原代碼 $list $this->model->with([admin, product])->where($where)->order($sort, $order)->paginate($limit);foreach ($list as $row) {$row->ge…

TCN+Transformer+SE注意力機制多分類模型 + SHAP特征重要性分析,pytorch框架

效果一覽 TCNTransformerSE注意力機制多分類模型 SHAP特征重要性分析 TCN&#xff08;時序卷積網絡&#xff09;的原理與應用 1. 核心機制 因果卷積&#xff1a;確保時刻 t t t 的輸出僅依賴 t ? 1 t-1 t?1 及之前的數據&#xff0c;避免未來信息泄露&#xff0c;嚴格保…

Elasticsearch的數據同步

elasticsearch中的數據多是來自數據庫&#xff0c;當數據庫發生改變時&#xff0c;elasticsearch也必須跟著改變&#xff0c;這個就叫做數據同步。 當我們是進行微服務的時候&#xff0c;同時兩個服務不能進行相互調用的時候。就會需要進行數據同步。 方法一&#xff1a;同步…

uniapp 時鐘

<template><view class"clock-view"><view class"clock-container u-m-b-66"><!-- 表盤背景 --><view class"clock-face"></view><!-- 時針 --><view class"hand hour-hand" :style&quo…

【大模型】實踐之1:macOS一鍵部署本地大模型

Ollama + Open WebUI 自動部署腳本解析說明文檔 先看下效果 一、腳本內容 #!/bin/bash set -eMODEL_NAME="qwen:1.8b" LOG_FILE="ollama_run.log" WEBUI_PORT=3000 WEBUI_CONTAINER_PORT=8080 WEBUI_URL="http://localhost:$WEBUI_PORT" DOC…

相機Camera日志實例分析之三:相機Camx【視頻光斑人像錄制】單幀流程日志詳解

【關注我&#xff0c;后續持續新增專題博文&#xff0c;謝謝&#xff01;&#xff01;&#xff01;】 上一篇我們講了&#xff1a; 這一篇我們開始講&#xff1a; 目錄 一、場景操作步驟 二、日志基礎關鍵字分級如下 三、場景日志如下&#xff1a; 一、場景操作步驟 操作步…

介紹一下 TCP方式程序的通訊,服務器機與客戶機

TCP通信方式&#xff1a;服務器與客戶機通信詳解 TCP(傳輸控制協議)是一種面向連接的、可靠的、基于字節流的傳輸層通信協議。下面我將詳細介紹TCP方式下服務器與客戶機的通信過程。 基本概念 TCP特點&#xff1a; 面向連接&#xff1a;通信前需建立連接可靠傳輸&#xff1a;…

Ubuntu系統復制(U盤-電腦硬盤)

所需環境 電腦自帶硬盤&#xff1a;1塊 (1T) U盤1&#xff1a;Ubuntu系統引導盤&#xff08;用于“U盤2”復制到“電腦自帶硬盤”&#xff09; U盤2&#xff1a;Ubuntu系統盤&#xff08;1T&#xff0c;用于被復制&#xff09; &#xff01;&#xff01;&#xff01;建議“電腦…