Spring 與 Mybatis 的事務管理


問題:Spring 與 Myabatis 整合后,為什么 DAO 不提交事務,但是數據能夠插入數據庫中?

  1. Mybatis 提供的連接池對象 —> 創建 Connection
    Connection.setAutoCommit(false) 手工的控制了事務,操作完成后,需要手工提交。
  2. Druid(C3P0、DBCP)作為連接池 —> 創建 Connection
    Connection.setAutoCommit(true) 默認值為 true,保持自動控制事務,一條 sql 自動提交。

答案:因為 Spring 與 Mybatis 整合時,引入了外部連接池對象,保持自動的事務提交這個機制Connection.setAutoCommit(true),不需要手工進行事務的操作,也能進行事務的提交。

注意:實戰中,還是會手工控制事務(多條SQL一起成功,一起失敗),后續 Spring 通過 事務控制 解決這個問題

1. 事務回顧

事務的 4 大特點: ACID

  • Atomicity 原子性
  • Consistency 一致性
  • Isolation 隔離性
  • Durability 持久性

如何控制事務?(JDBC、Mybatis)

JDBC
Connection.setAutoCommit(false);
Connection.commit();
Connection.rollback();
Mybatis

Mybatis 自動開啟事務
sqlSession.commit();,底層還是調用的 Connection
sqlSession.rollback();,底層還是調用的 Connection

2. Spring 中控制事務的開發

3. Spring 中的事務屬性(Transaction Attribute)

什么是事務屬性?

描述物體特征的一系列值(性別、身高、體重)

事務屬性:描述事務特征的一系列值

如何添加事務屬性?
@Transactional(isolation=, propagation=, readOnly=,timeout=,rollbackFor,noRollbackFor=,)

隔離屬性(ISOLATION)

描述了事務解決並發問題的特征。
  1. 什么是並發?
    多個事務(用戶)在同一時間,訪問操作了相同的數據。
    同一時間:0.000 幾秒左右
  2. 並發會產生那些問題?
    • 臟讀
    • 不可重復讀
    • 幻影讀
  3. 並發問題如何解決?
    通過隔離屬性解決,隔離屬性中設置不同過的值,解決並發處理的過程中的問題。
事務並發產生的問題:
  1. 臟讀
    一個事務,讀取了另一個事務中沒有提交的數據,會在本事務中產生數據不一樣的現象
    解決方案:@Transaction(isolation = Isolation.READ_COMMITTED)
  2. 不可重復讀
    一個事務中,多次讀取相同的數據,但是讀取結果不一樣,會在本事務中產生數據不一樣的現象
    注意:1.不是臟讀 2.在一個事務中
    解決方案:@Transaction(isolation = Isolation.REPEATABLE_READ)
    本質:一把行鎖(對數據庫表的某一行加鎖)
  3. 幻影讀
    一個事務中,多次對整表進行查詢統計,但是結果不一樣,會在本事務中產生數據不一致的問題
    解決方案:@Transaction(isolation = Isolation.SERIALIZABLE)
    本質:表鎖(對數據庫某個表加鎖)
安全與效率對比:
  • 並發安全:SERIALIZABLE > READ_ONLY > READ_COMMITTED
  • 運行效率:READ_COMMITTED > READ_ONLY > SERIALIZABLE
默認的隔離屬性:

Spring 默認會指定為 ISOLATION_DEFAULT,調用不同數據庫所設置的默認隔離屬性

  • MySQL:REPEATABLE_READ
  • Oracle:READ_COMMITTED

查看數據庫的默認隔離屬性:

  • MySQL:SELECT @@tx_isolation;
  • Oracle:較麻煩,建議百度。

隔離屬性在實驗中的建議

  • 推薦使用 Spring 默認指定的 ISOLATION_DEFAULT
  • 未來的實戰中,遇到並發訪問的情況,很少見
  • 如果真的遇到並發問題,解決方案:樂觀鎖
    Hibernate(JPA):version
    MyBatis:通過攔截器自定義開發

傳播屬性(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) 極其不常用
Spring 中傳播屬性的默認值是:REQUIRED

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

  • 增刪改 方法:使用默認值 REQUIRED
  • 查詢 方法:顯示指定傳播屬性的值為 SUPPORTS

只讀屬性(readOnly)

針對於 只進行查詢操作的業務方法,可以加入只讀屬性,提高運行效率。
默認值:false

@Transactional(readOnly = true)

超時屬性(timeout)

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

為什么事務會進行等待?
  1. 當前事務訪問數據時,有可能訪問的數據被別的事務進行加鎖的處理,那么此時本事務就必須進行等待。
  2. 等待時間:單位是 秒
  3. 如何使用:@Transactional(timeout = 2)
  4. 超時屬性的默認值:-1
    -1 表示超時屬性由對應的數據庫來指定(一般不會主動指定,-1 即可)

異常屬性

Spring 事務處理過程中:
  • 默認對於 RuntimeException 及其子類,采用 回滾 的策略。
  • 默認對於 Exception 及其子類,采用 提交 的策略。
使用方法:
@Transactional(rollbackFor = java.lang.Exception.class, xxx, xxx)
@Transactional(noRollbackFor = java.lang.RuntimeException, xxx, xxx)

事務屬性常見配置總結

  1. 隔離屬性:默認值
  2. 傳播屬性:Required(默認值)增刪改、Supports 查詢操作
  3. 只讀屬性:readOnly=false 增刪改,true 查詢操作
  4. 超時屬性:默認值 -1
  5. 異常屬性:默認值
開發建議

增刪改操作:@Transactional
查詢操作:@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM