Spring支持的常用數據庫事務傳播屬性和事務隔離級別?

請簡單介紹Spring支持的常用數據庫事務傳播屬性和事務隔離級別?

事務的屬性

  • propagation:用來設置事務的傳播行爲

    事務的傳播行爲:一個方法運行在了一個開啓了事務的方法中,當前方法是使用原來的事務還是開啓一個新的事務

    • Propagation.REQUIRED:默認值,使用原來的事務
    • Propagation.REQUIRES_NEW:將原來的事務掛起,開啓一個新的事務
  • isolation:用來設置事務的隔離級別

    • Isolation.REPEATEBLE_READ:可重複讀,MySQL默認的隔離級別
    • Isolation.READ_COMMITTED:讀已提交,Oracle默認的隔離級別,開發時通常使用的隔離級別

事務的傳播簡介

​ 當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼承在現有事務中運行,也可能開啓一個新事務,並在自己的事務中運行。

​ 事務的傳播行爲可以由傳播屬性指定。Spring定義了7種類型的傳播行爲。

傳播屬性 描述
REQUIRED (默認) 如果有事務在運行,當前的方法就在這個事務內運行,否則,就啓動一個新的事務,並在自己的事務內運行
REQUIRES_NEW 當前的方法必須啓動新的事務,並在它自己的事務內運行,如果有事務正在運行,應該將它掛起
SUPPORTS 如果有事務正在運行,當前的方法就在這個事務內運行。否則它可以不運行在事務中
NOT_SUPPORTED 當前的方法不應該運行在事務中。如果有運行的事務,將它掛起
MANDATORY 當前的方法必須運行在事務內部。如果沒有正在運行的事務,就拋出異常
NEVEER 當前的方法不應該運行在事務中。如果有運行的事務,就拋出異常
NESTED 如果有事務在運行,當前的方法就應該在這個事務的嵌套事務內運行。否則,就啓動一個新的事務,並在它自己的事務內運行

事務的傳播屬性可以在@Transactional註解的propagation屬性中定義。

(常用的是REQUIRED (默認)、REQUIRES_NEW這兩個)


示例

用戶表

id用戶id username用戶名 balance餘額
1 zhangsan 100.00

商品表

isbn書的編號 name書名 price單價
1001 三國演義 60.00
1002 西遊記 50.00

庫存表

isbn書的編號 stock庫存
1001 100
1002 100

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

分析

以上代碼中,checkout跟purchase方法都使用了事務,事務的傳播默認值是REQUIRED (默認,如果有事務在運行,當前的方法就在這個事務內運行),所以是使用checkout方法的事務。它購買了兩本書1001和1002,購買1001單價60的成功,但餘額變成了100-60=40,不足以購買1002的書,所以失敗,回滾。結果是,一本也沒有買到,數據庫數據不變。



在這裏插入圖片描述

在這裏插入圖片描述

分析

如果在purchase中添加了屬性Propagation.REQUIRES_NEW,就會開啓新的事務(當前的方法必須啓動新的事務,並在它自己的事務內運行,如果有事務正在運行,應該將它掛起),則將checkout事務掛起了,purchase使用自己的事務,這樣,1001書本會成功購買,庫存變爲99,用戶餘額變爲40,會買成功一本。1002單價是50,錢不夠,所以買不了。



事務的隔離級別

1. 數據庫事務併發問題

假設現在有兩個事務:Transaction01和Transaction02併發執行

  • 髒讀
    • Transaction01將某條記錄的AGE值從20修改爲30
    • Transaction02讀取了Transaction01更新後的值:30
    • Transaction01回滾,AGE值恢復到了20
    • Transaction02讀到的30就是一個無效的值
  • 不可重複讀
    • Transaction01讀取了AGE值爲20
    • Transaction02將AGE值修改爲30
    • Transaction01再次讀取AGE值爲30,和第一次讀取的不一致
  • 幻讀
    • Transaction01讀取了stu表中的一部分數據
    • Transaction02向stu表中插入了新的行
    • Transaction01讀取stu表時,多出了一些行

2. 事務的隔離級別

數據庫系統必須具有隔離併發運行各個事務的能力,使他們不會相互影響,避免各種併發問題。一個事務與其他事務隔離的程度稱爲隔離級別。SQL標準中規定了好多事務隔離級別,不同隔離級別對應不同的干擾程度,隔離級別越高,數據一致性就越好,但併發性越弱

  • 讀未提交:READ UNCOMMITTED

    ​ 允許Transaction01讀取Transaction02未提交的修改

    ​ (上面三種情況都不可避免)

  • 讀已提交:READ COMMITTED(常用的,其他事務已經提交的數據都認爲是真的)

    ​ 要求Transaction01只能讀取Transaction02已提交的修改

    (可避免髒讀)

  • 可重複讀:REPEATABLE READ

    ​ 確保Transaction01可以多次從一個字段中讀取到相同的值,即Transaction01執行期間禁止其他事務對這個字段進行更新。

    ​ (可避免髒讀,不可重複讀)

  • 串行化:SERIALIZABLE

    ​ 確保Transaction01可以從一個表中讀取到相同的行,在Transaction01執行期間,禁止其他事務對這個表進行增刪改操作。可以避免任何併發問題,但性能十分低下。

各個隔離級別解決併發問題的能力見下表

髒讀 不可重複讀 幻讀
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

各種數據庫產品對事務隔離級別的支持程度

Oracle MySQL
READ UNCOMMITTED x
READ COMMITTED √(默認)
REPEATABLE READ x √(默認)
SERIALIZABLE

示例:

可在@Transactional中添加isolation屬性

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章