MySQL事務及Spring隔離級別實現原理詳解
阿新 • • 發佈:2020-05-18
1、事務具有ACID特性
- 原子性(atomicity):一個事務被事務不可分割的最小工作單元,要麼全部提交,要麼全部失敗回滾。
- 一致性(consistency):資料庫總是從一致性狀態到另一個一致性狀態,它只包含成功事務提交的結果
- 隔離型(isolation):事務所做的修改在最終提交一起,對其他事務是不可見的
- 永續性(durability):一旦事務提交,則其所做的修改就會永久儲存到資料庫中。
2、事務的隔離級別
1)隔離級別的定義與問題
- READ UNCOMMITTED(讀未提交):事務的修改,即使沒有提交,對其他事務也都是可見的。事務能夠讀取未提交的資料,這種情況稱為髒讀。
- READ COMMITTED(讀已提交):事務讀取已提交的資料,大多數資料庫的預設隔離級別。當一個事務在執行過程中,資料被另外一個事務修改,造成本次事務前後讀取的資訊不一樣,這種情況稱為不可重複讀。
- PEPEATABLE READ(可重複讀):這個級別是MySQL的預設隔離級別,它解決了髒讀的問題,同時也保證了同一個事務多次讀取同樣的記錄是一致的,但這個級別還是會出現幻讀的情況。幻讀是指當一個事務A讀取某一個範圍的資料時,另一個事務B在這個範圍插入行,A事務再次讀取這個範圍的資料時,會產生幻行。特別說明:InnoDB和XtraDB儲存引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)解決了幻讀問題,它使用間隙鎖(next-key locking)鎖定查詢涉及的行和索引中的間隙,防止幻影行的插入。
- SERIALIZABLE(可序列化):這個事務是最高的隔離級別,它強制事務序列執行,避免了幻讀問題。簡單來說,SERIALIZABLE會在讀取的每一行資料上都加鎖,所以可能會導致大量的超時和鎖競爭
隔離級別 | 髒讀可能性 | 不可重複度可能性 | 幻讀可能性 | 加鎖讀 |
READ UNCONMITED | Yes | Yes | Yes | No |
RED COMMITED | No | Yes | Yes | No |
REPEATABLE READ | No | No | Yes | No |
SERIALIZABLE | No | No | No | Yes |
2)如果檢視修改和MySQL的隔離級別
show variables like 'tx_isolation'; # 檢視隔離級別,MySQL8以前 show variables like 'transaction_isolation'; # 檢視隔離級別,MySQL8 set global transaction_isolation='READ-COMMITTED'; // 設定隔離級別,閥域READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE
事務的隔離級別可以是Session層的,我們可以對不同的Session設定不同級別:
set session transaction isolation level read uncommitted; set session transaction isolation level read committed; set session transaction isolation level repeatable read; set session transaction isolation level serializable;
3)Spring事務隔離級別
Spring事務預設使用資料庫的隔離級別,可以通過註解@Transactional中的isolation引數調整Session級的隔離級別。隔離級別是會話級別的,JDBC的java.sql.Connection介面支援隔離級別的設定。
Spring在開啟事務時(DataSourceTransactionManager.doBegin),根據註解配置,對Connection的隔離級別進行設定:
MySQL驅動com.mysql.cj.jdbc.ConnectionImpl執行SQL語句調整會話級的隔離級別
3、死鎖
死鎖是指兩個或多個事務在同一資源上相互佔用,並請求鎖定對方佔用的資源,從而導致惡性迴圈。死鎖示例:
# 事務一 start transaction; update account set money=10 where id=1; update account set money=20 where id=2; commit; # 事務二 start transaction; update account set money=10 where id=2; update account set money=20 where id=1; commit;
假設碰巧,事務一和事務二同時執行完第一個update語句,接著準備執行第二條update語句,卻發現記錄已被對方鎖定,然後2個事務都等待對方釋放資源,同時持有對方需要的鎖,這樣就會出現死迴圈。
為了避免死鎖問題,資料庫實現了各種死鎖檢測和死鎖超長機制,InnoDB處理死鎖的方式是:將持有最少行級排他鎖的事務進行回滾。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。