Spring的事務傳播機制學錄
博客書
版本說明
spring.boot=2.2.5.RELEASE
相關鏈接:
- spring 事務官方說明:https://docs.spring.io/spring/docs/5.2.5.RELEASE/spring-framework-reference/data-access.html#spring-data-tier
- 驗證代碼地址:https://github.com/simba1949/spring-transactional-learn.git
Spring 事務傳播說明(主)
- 在不同類中各個事務具有事務傳播特性,非事務方法調用是事務方法有事務產生;事務方法調用事務方法,事務會在調用者和被調用者進行傳播;
- 在同一個類中,非事務方法調用事務方法無任何事務產生;事務方法調用事務方法只對當前調用方法產生事務;
驗證代碼Github地址:https://github.com/simba1949/spring-transactional-learn.git
備註:運行代碼需要查看控制日誌
- 事務創建:Creating new transaction with name
- 事務提交:Initiating transaction commit
- 支持當前事務:Participating in existing transaction
- 事務掛起:Suspending current transaction
- 事務恢復:Resuming suspended transaction
Spring 事務管理
數據庫事務(Database Transaction)是指將一系列數據操作當做一個邏輯處理單元的操作,這個單元中的數據庫操作要麼完全執行,要麼完全不執行。通過將一組相關操作組合作爲一個邏輯處理單元,可以簡化錯誤恢復,並使應用程序更加可靠。
事務的特性
- 原子性(Atomicity):一個事務內的操作,要麼全部執行成功,要麼全部執行不成功。
- 一致性(Consistency):事務執行後,數據庫狀態與其他業務規則保持一致。如轉賬業務,無論事務執行成功與否,參與轉賬的兩個賬號餘額之和是不變的。
- 隔離性(Isolation):每個事務獨立運行。在並環境下,併發的事務是互相隔離的,互不影響。
- 持久性(Durability):事務一旦提交後,數據庫中的數據必須被永久地保存下來。
事務的隔離級別
事務隔離級別越高,併發性能越差,但是安全性越高。
MySQL 事務隔離級別
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
read_uncommited (讀未提交) | √ | √ | √ |
read_commited (讀已提交) | × | √ | √ |
repeatable_read (可重複讀):默認 | × | × | √ |
serializable (串行化) | × | × | × |
Oracle 事務隔離級別
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
read_uncommited (讀未提交) | √ | √ | √ |
read_commited (讀已提交):默認 | × | √ | √ |
serializable (串行化) | × | × | × |
Spring 事務隔離級別
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
isolation_default | 同數據庫事務隔離級別 | 同數據庫事務隔離級別 | 同數據庫事務隔離級別 |
isolation_read_uncommited | √ | √ | √ |
isolation_read_commited | × | √ | √ |
isolation_repeatable_read | × | √ | √ |
isolation_serializable | × | × | × |
read_uncommited
讀未提交,即一個事務讀取到另一個事務未提交的數據。在 read_uncommited
隔離級別下,會造成“髒讀”;
假設場景,有 A、B兩個事務同時對一個賬戶進行存款和取款操作,A 事務向賬戶存款 10元,B 事務從賬戶取款 10元。
時間軸 | 事務A存款 | 事務B取款 |
---|---|---|
T1 | 事務A開始 | —— |
T2 | —— | 事務B開始 |
T3 | —— | 事務B查詢餘額(餘額爲10元) |
T4 | —— | 事務B取出10(餘額爲0元) |
T5 | 事務A查詢餘額(餘額爲0元) | —— |
T6 | —— | 事務B撤銷(餘額爲10元) |
T7 | 事務A存入10元 | —— |
T8 | 事務A提交(餘額更新爲10元) |
正常情況下,A、B事務執行完之後,賬戶餘額應爲20元,但是在時刻T5時,事務A查詢到的餘額爲0元,這是因爲讀到事務B未提交的數據,即髒讀。
read_commited
讀已提交,在 read_commited
隔離級別下,可以有效避免“髒讀”。雖然解決了“髒讀”問題,但是無法避免不可重複讀。
假設場景
時間軸 | 事務A查詢 | 事務B取款 |
---|---|---|
T1 | 事務A開始 | —— |
T2 | —— | 事務B開始 |
T3 | —— | 事務B查詢餘額(餘額爲10元) |
T4 | 事務A查詢餘額(餘額爲10元) | —— |
T5 | —— | 事務B取出10元(餘額爲0元) |
T6 | —— | 事務B提交 |
T7 | 事務A查詢餘額(餘額爲0元) | —— |
T8 | 事務A提交 |
事務A執行了兩次餘額查詢,但第一次查詢得到的餘額爲10元,第二次查詢得到的餘額爲0元,這就是不可重複讀的問題。
repeatable_read
可重複讀級別是保證在事務處理過程中多次讀取統一數據時的值始終是一致的。可重複讀取是通過在事務開啓後不允許其他事務對當前記錄進行修改操作。
repeatable_read
隔離級別可以有效地避免“髒讀”和不可重複讀的問題,但是有可能會出現“幻讀”。
假設場景
時間軸 | 事務A查詢記錄 | 事務B取款 |
---|---|---|
T1 | 事務A開始 | —— |
T2 | —— | 事務B開始 |
T3 | 查詢交易記錄 | —— |
T4 | —— | 事務B存入10元 |
T5 | —— | 事務B提交 |
T6 | 查詢交易記錄 | —— |
T7 | 提交事務 | —— |
在事務A中,同一個事務多次獲取交易記錄,發現第二次獲取交易記錄的結果中多存了一筆存款記錄(事務B發生的存款操作),對於事務A來說,好像出現了幻覺一樣,即“幻讀”。
serializable
串行化是最嚴格地事務隔離級別。它要求所有的事務排隊依序執行,即事務只能一個接一個的處理,不能併發執行。
假設場景
時間軸 | 事務A存款 | 事務B取款 |
---|---|---|
T1 | 事務A開始 | —— |
T2 | 事務A查詢餘額(餘額爲0元) | —— |
T3 | 事務A存入10元 | —— |
T4 | 事務A提交 | —— |
T5 | —— | 事務B開始 |
T6 | —— | 事務B查詢餘額(餘額爲10元) |
T7 | —— | 事務B取出10元 |
T8 | —— | 事務B提交 |
Spring七種事務傳播行爲
https://docs.spring.io/spring/docs/5.2.5.RELEASE/spring-framework-reference/data-access.html#tx-propagation
事務傳播行爲是用來描述由某一個事務傳播行爲修飾的方法被嵌套進另一個方法的時候。
事務傳播行爲類型 | 說明 |
---|---|
PROPAGATION_REQUIRED | 如果當前沒有事務,就新創建一個事務。 如果已經存在一個事務中,加入到這個事務中。 |
PROPAGATION_SUPPORTS | 支持當前事務。如果當前沒有事務,就以非事務方式執行。 |
PROPAGATION_MANDATORY | 使用當前事務。如果當前沒有事務,就拋出異常。 |
PROPAGATION_REQUIRES_NEW | 新創建事務。如果當前存在事務,就把當前事務暫時掛起。 |
PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作。如果當前存在事務,就把當前事務暫時掛起。 |
PROPAGATION_NEVER | 以非事務方式執行操作。如果當前存在事務,則拋出異常。 |
PROPAGATION_NESTED | 如果當前存在事務,則在嵌套事務內執行。 如果當前沒有事務,則執行 PROPAGATION_REQUIRED 類似操作與 PROPAGATION_REQUIRES_NEW 的差別 PROPAGATION_REQUIRES_NEW 另起一個事務,將會與其父事務互相獨立。PROPAGATION_NESTED 事務和其父事務是相依的,其要等父事務一起提交。 |
Spring 事務傳播說明
- 在不同類中各個事務具有事務傳播特性,非事務方法調用是事務方法有事務產生;事務方法調用事務方法,事務會在調用者和被調用者進行傳播;
- 在同一個類中,非事務方法調用事務方法無任何事務產生;事務方法調用事務方法只對當前調用方法產生事務;