mysql事務隔離級別/臟讀/不可重復讀/幻讀詳解


一、四種事務隔離級別

1.1 read uncommitted 讀未提交

即:事務A可以讀取到事務B已修改但未提交的數據。

除非是文章閱讀量,每次+1這種無關痛癢的場景,一般業務系統沒有人會使用該事務隔離級別,標准實在太寬松了。

 

1.2 read committed 讀已提交(簡稱RC)

即:事務A只能讀取到事務B修改並已提交的數據。

這個級別相對要嚴格一些,至少是要等其它事務把變更提交到db,才能讀取到,聽上去蠻靠譜的。但是有些業務場景,比如會員系統中,如果要在一個事務中,多次讀取用戶身份,判斷是否會員,如果剛開始讀取到該用戶是會員,做了一些邏輯處理,后面又讀到用戶不是會員了,這就有點崩潰,不知道如何繼續。這種希望同1個事務中,關鍵數據不管讀取多次次,結果都一樣,RC級別就不行了。


1.3 repeatable read 可重復讀

即:同一個事務中,多次讀取某一行記錄,始終是一樣的值,不管在此期間,其它事務有沒有修改過該數據(不論是否提交)。該級別解決了RC不可重復讀的問題,但是存在幻讀問題(幻讀后面會詳解)。

 

1.4 serializable 串行化

即:一個事務在修改其它數據時,如果有其它事務也想改,必須等前面的事務提交或回滾后,才能繼續。最嚴格的級別,但是性能最低,也幾乎沒人用。

 

二、臟讀/不可重復讀/幻讀
2.1 臟讀

 

驗證:

a. 找一個mysql環境,建一個測試表t_people,就2列 id ,name

b. 開二個mysql終端,連到db上,為方便講解,這2個終端稱為“終端1”、“終端2”,終端1里輸入:

set session transaction isolation level read uncommitted;
start transaction;

即:設置當前會話的隔離級別為"讀未提交"。

終端2里,輸入:

start transaction;
update t_people set name='xxx' where id=1;

然后再回到“終端1”,執行 

select id,name from t_people where id=1;

可以看到,讀取到了未提交的臟數據 。 終端2里,此時如果執行rollback回滾 

終端1里,繼續執行

select id,name from t_people where id=1;

可以發現最新結果,已經是回滾后的數據。很顯然:如果有臟讀問題出現,就更加保證不了“可重復讀”。

 

2.2 不可重復讀

 

將事務隔離級別設置成read committed(即:讀已提交),可解決臟讀問題,但滿足不了“可重復讀需求”。

驗證方法跟剛才類似,終端1里輸入:

set session transaction isolation level read committed;

將級別設置成RC,然后2個終端里都開啟事務,終端2中,修改一行數據,但是不提交,此時終端1里應該是讀不到終端2修改的數據。然后終端2提交,終端1才能讀到修改后的數據。終端2如果繼續修改、提交,終端1里再讀取這1行,將是最新的值。(也就是只說,只要終端2不斷修改,不斷提交,終端1里就能讀到這行不同的新值,即:保證不了同1個事務中,同一行數據,多次重復讀取的值不變)

 

2.3 幻讀

將隔離級別繼續調整至Repeatable Read,還是剛才的場景,變成這樣:

 

事務A對於同一行數據,不管讀多少次,始終是相同的值,完全不理會有沒有其它事務在修改它。有點:“兩耳不聞窗外事,一心只讀聖賢書”的味道。但是這也有問題,比如秒殺訂單系統中,事務A第1次讀取商品庫存,發現還有1個,可以下單,趕緊繼續,但是此時,可能有另一個事務,也在下單,已經提交了訂單,把庫存減為0了,事務A並不知道,因為多次讀取庫存的值是一樣的,還是1,最后仍然把訂單創建了,形成超賣。

驗證方法:

set session transaction isolation level repeatable read;

剩下的步驟跟前面類似,就不重復贅述了。 

 

2.4 串行化

從db層面,要想同時解決臟讀、不可重復讀、幻讀,只有串行化這個級別可以做到。

set session transaction isolation level serializable;

如下圖:終端1設置串行化后,緊接着select xxx where id=1這條語句后,id=1的這行記錄,就被鎖了。

在終端2里,更新其它記錄(即:id不等於1)可以正常成功,但是更新id=1 時,就會卡住,除非終端1把事務提交或回滾,否則將一直卡着,直到超時失敗。

 

小結

隔離級別   存在的問題
讀未提交    臟讀、不可重復讀、幻讀
讀已提交   不可重復讀、幻讀
可重復讀 幻讀
串行化 性能問題

隔離級別越嚴格,db綜合性能越低。

 

建議:

大多數情況下,RC(讀已提交)基本上就足夠了,如果並發度高,可以考慮“RC級別+(應用層)分布式鎖”,這樣即能保證數據正確,對db的性能壓力也較低。


免責聲明!

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



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