Spring5學習隨筆-事務屬性詳解(@Transactional)

来源:https://www.cnblogs.com/eyewink/archive/2023/11/21/17846325.html
-Advertisement-
Play Games

事務是保證業務操作完整性的一種資料庫機制,具有原子性、一致性、隔離性和持久性(ACID)的特點。 在Java中,可以通過JDBC和MyBatis來控制事務,底層都是通過Connection對象完成的。 Spring使用AOP的方式進行事務開發,通過將事務的額外功能封裝在DataSourceTrans... ...


學習視頻:【孫哥說Spring5:從設計模式到基本應用到應用級底層分析,一次深入淺出的Spring全探索。學不會Spring?只因你未遇見孫哥】

第三章、Spring的事務處理

1.什麼是事務?

事務是保證業務操作完整性的一種資料庫機制
事務的4特點:ACID

  1. A 原子性
  2. C 一致性
  3. I 隔離性
  4. D 持久性

2.如何控制事務

JDBC:

Connection.setAutoCommit(false)

Connection.commit();

Connection.rollback();

Mybatis:

Mybatis自動開啟事務

SqlSession(底層還是Connection).commit();

sqlSession(底層還是Connection).rollback();

結論:控制事務的底層 都是Connection對象完成的

3.Spring控制事務的開發

Spring是通過AOP的方式進行事務開發

  1. 原始對象

    public class XXXUserServiceImpl{
    	1.原始對象 ---> 原始方法  --->核心功能(業務處理+DAO調用)
    	2.DAO作為Service的成員變數,依賴註入的方式進行賦值
    }
    
  2. 額外功能

    下麵的額外功能封裝在org.springframework.jdbc.datasource.**DataSourceTransactionManager
    應用的過程需要註入DataSource**
    
    1.MethodInterceptor
    public Object invoke(MethodInvocation invocation){
    	try{
    		Connection.setAutoCommit(false);
    		Object ret = invocation.proceed();
    		Connection.commit();
    		return ret;
    	}catch(Exception e){
    		Connection.rollback();
    	}
    }
    2. @Aspect
    	 @Around
    
  3. 切入點

    @**Transactional**
    事務的額外功能能加入給那些業務方法
    
    1. 類上:類中所有的方法都會加入事務
    2. 方法上:這個方法加入事務
    
  4. 組裝切麵

    1. 切入點
    2. 額外功能

    <tx:annotation-driven transaction-manager=””/>

4.Spring控制事務的編碼

  • 搭建開發環境(jar)
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.1.14.RELEASE</version>
</dependency>
  • 編碼
<!-- 1. 原始對象-->
<bean id="userService" class="com.baizhi.service.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
</bean>
<!-- 2. 額外功能-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

3.切入點
@Transactional
public class UserServiceImpl implements UserService {
    private UserDao userDao;
<!--
    4.組裝
    選擇結尾是/tx的driven
-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
  • 細節

    <tx:annotation-driven transaction-manager="dataSourceTransactionManager" proxy-target-class="true"/>

    進行動態代理底層實現的切換 proxy-target-class

    預設false:JDK true: Cglib

第四章、Spring中的事務屬性(Transaction Attribute)

1.什麼是事務屬性

屬性:描述物體特征的一系列值

性別 身高 體重…

所謂的事務屬性指的是描述事務特征的一系列值

  1. 隔離屬性
  2. 傳播屬性
  3. 只讀屬性
  4. 超時屬性
  5. 異常屬性

2.如何添加事務屬性

@Transactional(isolation(隔離屬性)=,propagation(傳播屬性)=,readOnly(只讀屬性)=,timeout(超時屬性)=,rollbackFor=,noRollbackFor=);

3.事務屬性詳解

1.隔離屬性(ISOLATION)

  • 隔離屬性的概念

    概念:他描述了事務解決併發問題的特征

    1. 什麼是併發

      指的是多個事務(用戶)在同一時間,訪問操作了相同的數據

      重點 同一時間:微小的時間內 0.0000幾秒 微小前、後

    2. 併發會產生那些問題

      1. 臟讀
      2. 不可重覆讀
      3. 幻影讀
    3. 併發問題如何解決

      通過隔離屬性解決,隔離屬性設置不同的值,解決併發處理過程中的問題。

  • 事務併發產生的問題

    • 臟讀

      指的是一個事務/用戶讀取了另外一個事務/用戶中沒有提交的數據。會在本事務中產生不一致的問題

      解決方案:@Transactional(isolation=Isolation.READ.COMMITTED)

      本質:只讀取已提交的數據

    • 不可重覆讀

      一個事務中,多次讀取相同的數據,但是讀取結果不一樣,會在本事務中產生數據不一致的問題

      註意:1.不是臟讀 2.在一個事務中

      解決方案:@Transactional(isolation=Isolation.REPEATABLE_READ)

      本質:對應資料庫底層的行鎖(第一個人在讀取數據時,其他人都得等第一個人處理完)

    • 幻影讀

      一個事務中,多次對整表進行查詢統計,但是結果不一樣,會在本事務中產生數據不一致的問題。

      解決方案:@Transactional(isolation=Isolation.SERIALIZABLE)

      本質對應資料庫底層的表鎖

    • 總結

      併發安全:SERIALIZABLE>REPEATABLE_READ>READ.COMMITTED

      運行效率:READ.COMMITTED>REPEATABLE_READ>SERIALIZABLE

  • 資料庫對於隔離屬性的支持

    隔離屬性的值 MySQL Oracle
    Isolation.READ.COMMITTED ✔️ ✔️
    Isolation.REPEATABLE_READ ✔️
    Isolation.SERIALIZABLE ✔️ ✔️

    Oracle不支持REPETABLE_READ值 採用的是多版本比對的方式 解決不可重覆讀的問題

  • 預設隔離屬性

    ISOLATION_DEFAULT:會調用不同資料庫所設置的預設隔離屬性

    例如:如果使用MYSQL 預設隔離屬性:REPEATABLE_READ,Oracle:READ_COMMITTED

    • 查看資料庫預設隔離屬性
      • MySQL

        8.0版本以前:select @@tx_isolation
        8.0版本之後:select @@transaction_isolatio
        
  • 隔離屬性在實戰中的建議

    推薦使用Spring指定的ISOLATION——DEFALUT

    1. MySQL repeatbale_read
    2. Oracle READ_COMMITED

    未來中的實戰中,併發訪問情況 很低(前提就是海量用戶

    如果真遇到併發問題,可以使用樂觀鎖

    Hibernate(JPA) Version

    MyBatis 通過攔截器自定義開發

2.傳播屬性(PROPAGATION)

  • 傳播屬性的概念

    概念:他描述了事務解決嵌套問題的特征

    什麼叫做事物的嵌套:他指的是一個大的事務中,包含若幹個小的事務

    問題:大事務中融入了很多小的事務,他們彼此影響,最終導致外部大的事務,喪失了事務的原子性

  • 傳播屬性的值及其用法

    不管屬性是什麼,其中心思想是保證同一時間只會有一個事務的存在

    傳播屬性的值 外部不存在事務 外部存在事務 用法 備註
    REQUIRED 開啟新的事務 融合到外部事務中 @Transactional(propagation=Propagation.REQUIRED 主要應用於增刪改方法
    SUPPORTS 不開啟新的事務 融合到外部事務中 @Transactional(propagation=Propagation.SUPPORTS 一般應用查詢方法中
    REQUIRES_NEW 開啟新的事務 掛起外部事務,創建新的事務 @Transactional(propagation=Propagation.REQUIRES_NEW 日誌記錄方法中
    NOT_SUPPORTED 不開啟新的事務 掛起外部事務 @Transactional(propagation=Propagation.NOT_SUPPORTED 極其不常用
    NEVER 不開啟新的事務 拋出異常 @Transactional(propagation=Propagation.NEVER 極其不常用
    MANDATORY 拋出異常 融合到外部事務中 @Transactional(propagation=Propagation.MANDATORY 極其不常用

融合指的是:放棄自己的事務,以外部的事務為準

  • 預設的傳播屬性

    REQUIRED是傳播屬性的預設值

  • 推薦傳播屬性的使用方式

    增刪改 方法:直接使用預設值REQUIRED

    查詢 操作:顯示指定傳播屬性的值SUPPORTS

3.只讀屬性(readOnly)

針對於只進行查詢操作的業務方法,可以加入只讀屬性,提供運行效率

預設值:false

4.超時屬性(timeout)

指定了事務等待的最長時間

  1. 為什麼事務要進行等待呢?

    因為在當前事務訪問數據時,有可能訪問的數據是被別的事務進行加鎖的處理,那麼此時本事務就必須進行等待

  2. 等待時間:秒

  3. 如何應用 @Transactional(timeout=2)

  4. 超時屬性的預設值:-1

    最終由對應的資料庫來指定預設值,一般使用預設值

5.異常屬性

Spring事務處理過程中

預設 對於RuntimeException及其子類 採用的是回滾的策略

預設 對於Exception及其子類 採用的是提交的策略

想要改變預設的策略,可以設置兩個屬性

  1. rollbackFor(回滾) ={java.lang.Exception,xxx,……};
  2. noRollbackFor(不回滾)=
@Transactional(rollbackFor = {Exception.class},noRollbackFor = {RuntimeException.class})

建議:實戰中使用RuntimeException及其子類 使用事務異常屬性的預設值,實際開發很少改變策略

4.事務屬性常見配置總結

  1. 隔離屬性 預設值
  2. 傳播屬性 Required(預設值)增刪改 Supports 查詢操作
  3. 只讀屬性 readOnly false 增刪改 查詢用true
  4. 超時屬性 預設值:-1
  5. 異常屬性 預設值

後續實戰當中的建議:增刪改操作 @Transactional

而對於查詢操作 @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)

5.基於標簽的事務配置方式(事務開發的第二種形式)

  • 基於註解 @Transaction的事務配置回顧
<!-- 1. 原始對象-->
<bean id="userService" class="com.baizhi.service.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
</bean>
<!-- 2. 額外功能-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

3.切入點
@Transactional
public class UserServiceImpl implements UserService {
    private UserDao userDao;
<!--
    4.組裝
    選擇結尾是/tx的driven
-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
  • 基於標簽的事務配置
<!-- 1. 原始對象-->
<bean id="userService" class="com.baizhi.service.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
</bean>
<!-- 2. 額外功能-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!-- 第三步 事務屬性 -->
<tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager">
		<tx:attributes>
				<tx:method name="register" isolation="DEFAULT" propagation=""/>
				<tx:method name="login"...../>
		</tx:attributes>
</tx:advice>

<!-- 第四步 指定切入點-->
<aop:config>
		<aop:pointcut id="pc" expression="execution(* com.baizhi.service.UserServiceImpl.register(..))"/>
		<aop:advisor advice-ref="" pointcut-ref="">
</aop:config>
  • 基於標簽的事務配置在實戰中的應用方式

    <!-- 1. 原始對象-->
    <bean id="userService" class="com.baizhi.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>
    <!-- 2. 額外功能-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    **編程的時候 service 負責進行增刪改操作的方法 都以modify開頭
    						查詢操作 命名無所謂  用*號代替
    可以將特殊事務的事務放在前面**
    <tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager">
    		<tx:attributes>
    				<tx:method name="register" />
    				<tx:method name="modify*"/>
    				<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
    		</tx:attributes>
    </tx:advice>
    
    <!-- 第四步 指定切入點-->
    使用包切入點,應用的過程中 service放置到service包中
    <aop:config>
    		<aop:pointcut id="pc" expression="execution(* com.baizhi.service..*.*(..))"/>
    		<aop:advisor advice-ref="" pointcut-ref="">
    </aop:config>
    

作者:揚眉劍出鞘
出處: https://www.cnblogs.com/eyewink/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


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

-Advertisement-
Play Games
更多相關文章
  • 本章以實時OALP引擎Clickhouse(簡稱ck)為例, 以其面向場景, 架構設計, 細節實現等方面來介紹, 深度瞭解其如何成為了OLAP引擎中的性能之王. ...
  • 本文首發於公眾號:Hunter後端 原文鏈接:Django筆記四十二之model使用validator驗證器 這一篇筆記介紹一下 model 里的 validator 驗證器。 首先,這是個什麼東西呢? 在 model 的第四篇筆記里,我們介紹了欄位的一些屬性,比如是否允許為空,varchar 類型 ...
  • Lambda表達式 Lambda是一個匿名函數,我們可以把Lambda表達式理解為是一段可以傳遞的代碼(將代碼像數據一樣進行傳遞)。使用它可以寫出更簡潔、更靈活的代碼。作為一種更緊湊的代碼風格,使Java的語言表達能力得到了提升。 本質: 作為函數式介面的實例, 沒有介面就沒意義了. // 簡單使用 ...
  • keycloak目前提供了幾種分散式緩存,我們自己的緩存,如果希望是分散式的,可以將緩存添加到以下幾個緩存里即可 actionTokens clientSessions loginFailures offlineClientSessions offlineSessions sessions work ...
  • 一、讀取寫入視頻文件 1 import cv2 2 3 # 創建一個視屏捕獲對象 4 videoCapture = cv2.VideoCapture('AVI.avi') 5 6 # 獲取視頻的屬性值,cv2.CAP_PROP_FPS獲取視頻幀率 7 fps = videoCapture.get(c ...
  • 題目: 給你兩個按 非遞減順序 排列的整數數組 nums1 和 nums2,另有兩個整數 m 和 n ,分別表示 nums1 和 nums2 中的元素數目。 請你 合併 nums2 到 nums1 中,使合併後的數組同樣按 非遞減順序 排列。 註意:最終,合併後數組不應由函數返回,而是存儲在數組 n ...
  • AcWing 演算法基礎課week 1 總結 總結點 1:快速排序(分治思想) 題1:從小到大排序 主體思路:定義一個數x屬於數組s,利用雙指針,將數組分為大於等於x和小於等於x的兩部分,然後遞歸處理。(具體步驟如下) 1. 如上圖所示,我們定義一個數組s用來儲存n個數據,然後定義兩個指針i j,分別 ...
  • Assistants介紹 隨著OpenAI將Assistants助手API對外發佈,我們搭建個人知識庫變的如此簡單。開發者將自己的應用通過Assistants API與OpenAI對接,就可以讓每一位客戶擁有不一般體驗的個人知識庫。由於Assistants相關API有30+,本文只列舉完成一個最小功 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...