spring-transaction源碼分析(3)Transactional事務失效原因

来源:https://www.cnblogs.com/xugf/archive/2023/05/11/17390167.html
-Advertisement-
Play Games

問題概述 在Transactional方法中使用this方式調用另一個Transactional方法時,攔截器無法攔截到被調用方法,嚴重時會使事務失效。 類似以下代碼: @Transactional public void insertBlogList(List<Blog> blogList) { ...


問題概述

在Transactional方法中使用this方式調用另一個Transactional方法時,攔截器無法攔截到被調用方法,嚴重時會使事務失效。

類似以下代碼:

@Transactional
public void insertBlogList(List<Blog> blogList) {
  for (Blog blog : blogList) {
    this.blogMapper.insertBlog(blog);
  }
  try {
    TimeUnit.SECONDS.sleep(15);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}

@Transactional
public void deleteBlogByCondition(BlogSearchParameter parameter) {
  List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
  for (Blog blog : blogs) {
    this.blogMapper.deleteBlog(blog.getId());
  }
  // 拋出一個RuntimeException
  throw new RuntimeException("deleteBlogByCondition拋出一個異常");
}

@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {

  // 插入數據
  this.insertBlogList(blogList);

  // 刪除數據
  try {
    this.deleteBlogByCondition(parameter);
  } catch (Exception e) {
    System.err.printf("Err:%s%n", e.getMessage());
  }

  System.out.println("繼續插入數據");

  // 繼續插入數據
  this.insertBlogList(blogList);
}

正常情況下,執行到"繼續插入數據"時會拋出一個"rollback only"的異常,然後事務回滾。

而現在的現象是:

  • 三個操作都不會開啟事務,出現異常也不會回滾
  • "刪除數據"操作會把符合條件的數據都刪除掉
  • "繼續插入數據"操作會再插入數據

原因分析

在EnableTransactionManagement註解mode屬性的文檔中:

The default is AdviceMode.PROXY. Please note that proxy mode allows for interception of calls through the proxy only.
Local calls within the same class cannot get intercepted that way; an Transactional annotation on such a method within 
a local call will be ignored since Spring's interceptor does not even kick in for such a runtime scenario.
For a more advanced mode of interception, consider switching this to AdviceMode.ASPECTJ.

大概意思是:mode屬性的預設值是AdviceMode.PROXY,這種方式僅允許通過代理對來調用事務方法,同一個類的本地調用無法被事務切麵攔截。如果要解決這個問題,可以使用AdviceMode.ASPECTJ模式。

其實這個問題的根本原因與spring-tx無關,而是spring-aop的實現方式造成的。

從spring-aop攔截器分析問題原因

在DynamicAdvisedInterceptor和JdkDynamicAopProxy中有一段類似的代碼:

其中target就是原始的業務層Bean對象。

在後續創建ReflectiveMethodInvocation/CglibMethodInvocation時又將此target傳遞了進去:

// JDK
MethodInvocation invocation =
		new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();

// Cglib
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

proceed方法中在攔截器鏈最後會調用目標方法:

public Object proceed() throws Throwable {
	// We start with an index of -1 and increment early.
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}

	// 略
}

protected Object invokeJoinpoint() throws Throwable {
	// 反射調用目標方法
	// 這個target就是原始Bean對象
	return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

所以如果在目標方法中使用this方法調用另一個需要被攔截的方法,將不會執行攔截邏輯。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JScrollPane 組件() 功能介紹: 當容器的顯示區域不足以同時顯示所有組件的時候,滾動面版JScrollPane(後省略為JS)可以通過滾動的方式將組件的內容展示出來。 使用方法: JS通過將一些組件先添加到JPanel中,再將JPanel添加到JS上,而JTextArea、JList、J ...
  • #用Python實現藝術繪畫 藝術繪畫是一個創造性的過程,包括繪畫、素描和繪畫。藉助Python編程語言,您可以模擬藝術繪畫的過程。該過程包括以下步驟: 1.導入所需的庫-您需要導入NumPy、OpenCV和Matplotlib等庫來執行圖像處理任務。 2.載入圖像-您可以使用OpenCV載入圖像。 ...
  • Neo4j是一個高性能的開源的,使用Java語言實現的NoSQL圖資料庫,它將結構化數據存儲在網路上而不是表中。它是一個嵌入式的、基於磁碟的、具備完全的事務特性的Java持久化引擎,但是它將結構化數據存儲在網路(從數學角度叫做圖)上而不是表中。 ...
  • ElasticSearch 索引設計 在MySQL中資料庫設計非常重要,同樣在ES中資料庫設計也是非常重要的 概述 我們創建索引就像創建表結構一樣,必須非常慎重的,索引如果創建不好後面會出現各種各樣的問題 索引設計的重要性 索引創建後,索引的分片只能通過_split和_shrink介面對其進行成倍的 ...
  • 用go設計開發一個自己的輕量級登錄庫/框架吧(項目維護篇) 本篇將開始講講開發庫/框架的最開始階段,也就是搭建一個項目 源碼:weloe/token-go: a light login library (github.com) 項目結構 項目結構,不是上一篇所說的代碼架構,而是分包,明確的分包更有助 ...
  • 一、問題引入 閱讀UNIX網路編程 捲1:套接字聯網API 第3版的前4個章節,覺得有必要對書籍上的源碼案例進行復現,並推敲TCP的C/S通信過程。 二、解決過程 2-1 server #include <sys/types.h> #include <sys/socket.h> #include < ...
  • Go 資料庫編程 一、連接資料庫 準備連接到資料庫 要想連接到 SQL 資料庫,首先需要載入目標資料庫的驅動,驅動裡面包含著於該資料庫交互的邏輯。 sql.Open() 資料庫驅動的名稱 數據源名稱 得到一個指向 sql.DB 這個 struct 的指針 sql.DB 是用來操作資料庫的,它代表了0 ...
  • 時隔20天,OpenAI從v0.0.1升級到了v0.2.0。與v0.0.1版相比,v0.2.0版主要做了以下改動: 把cmd目錄下微信公眾號的相關服務遷移到了這裡 完善了cmd下的測試服務,針對openAI庫里實現的各個介面都提供了響應的調用介面,服務運行後可以通過postman進行測試 完成了Fi ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...