一文讀懂MySQL事務(wù)隔離級(jí)別和鎖的關(guān)系

預(yù)備知識(shí)

mysql5.5以上版本中默認(rèn)使用的存儲(chǔ)引擎是基于InnoDB,所以本文所有關(guān)機(jī)都是基于InnoDB存儲(chǔ)引擎。

  1. 行鎖:顧名思義,該鎖鎖住的是表中數(shù)據(jù)的某一行數(shù)據(jù),共享鎖和互斥鎖都屬于行鎖。另外行鎖可以使用的前提條件是SQL語(yǔ)句必須使用到了索引(如果不知道何為索引,可以先了解一下,當(dāng)然不了解也不影響理解后面的知識(shí)),否則不會(huì)使用行鎖,而是使用表鎖。

    • 共享鎖(S):共享鎖也稱(chēng)為讀鎖,共享鎖和共享鎖之間是兼容的,但和排他鎖不兼容。什么意思呢?假設(shè)事務(wù)A加了一個(gè)共享鎖,那么事務(wù)B是可以申請(qǐng)共享鎖的,但是不可以申請(qǐng)排它鎖。這里要注意一點(diǎn),并不是說(shuō)一定要獲取共享鎖才能讀取數(shù)據(jù),這里得看數(shù)據(jù)庫(kù)是如何實(shí)現(xiàn)的,后面講事務(wù)隔離級(jí)別的時(shí)候會(huì)講到,先提前挖個(gè)坑。

    • 排他鎖(X):排它鎖也稱(chēng)為寫(xiě)鎖,排他鎖與排他鎖以及共享鎖均不兼容。假設(shè)事務(wù)A加了一個(gè)排它鎖,那么其他事務(wù)既不能申請(qǐng)共享鎖,也不能申請(qǐng)排它鎖。

  2. 表鎖:該鎖鎖住的是表中的所有數(shù)據(jù)。意向共享鎖和意向排它鎖屬于表鎖。

    • 意向共享鎖(IS):事務(wù)在給一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的 IS 鎖。

    • 意向排他鎖(IX):事務(wù)在給一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的 IX 鎖。

鎖模式的兼容情況:

InnoDB加鎖方法:

  • 意向鎖是 InnoDB 自動(dòng)加的, 不需用戶(hù)干預(yù)。

  • 對(duì)于 UPDATE、 DELETE 和 INSERT 語(yǔ)句, InnoDB 會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X);

  • 對(duì)于普通 SELECT 語(yǔ)句,InnoDB 不會(huì)加任何鎖(SERIALIZABLE隔離級(jí)別除外); 事務(wù)可以通過(guò)以下語(yǔ)句顯式給記錄集加共享鎖或排他鎖:

    (1)SELECT ... LOCK IN SHARE MODE;

    (2)SELECT ... FOR UPDATE;

MVCC

每個(gè)連接到數(shù)據(jù)庫(kù)的讀者,在某個(gè)瞬間看到的是數(shù)據(jù)庫(kù)的一個(gè)快照,寫(xiě)者寫(xiě)操作造成的變化在數(shù)據(jù)庫(kù)事務(wù)提交之前對(duì)于其他的讀者來(lái)說(shuō)是不可見(jiàn)的。

事務(wù)的隔離級(jí)別

事務(wù)有四種隔離級(jí)別,不同的隔離級(jí)別對(duì)應(yīng)的加鎖策略是不一樣的,這就導(dǎo)致不同的隔離級(jí)別,解決并發(fā)的能力有所差異。另外還有一個(gè)地方要注意的是某個(gè)事務(wù)如果申請(qǐng)成功一把行鎖,就會(huì)立即給行加上該鎖。

  • READ UNCOMMITTED(未提交讀): 在該隔離級(jí)別下,事務(wù)的讀操作不申請(qǐng)共享鎖,寫(xiě)操作申請(qǐng)排它鎖,并在事務(wù)結(jié)束后釋放,導(dǎo)致一個(gè)事務(wù)中的讀操作可以讀到另一個(gè)事務(wù)中還未提交的寫(xiě)操作(臟讀)。注意在該隔離級(jí)別下,讀取未提交的更新不會(huì)被排它鎖阻止,因?yàn)樽x取操作不用申請(qǐng)任何鎖,可以直接讀取數(shù)據(jù)。
  • READ COMMITTED(已提交讀):在該隔離級(jí)別下,事務(wù)的讀操作不申請(qǐng)共享鎖,但是讀取的數(shù)據(jù)是最新的一份快照數(shù)據(jù),寫(xiě)操作申請(qǐng)排它鎖,并在事務(wù)結(jié)束后釋放,導(dǎo)致在一個(gè)事務(wù)中讀取相同的數(shù)據(jù)可能得到不一樣的結(jié)果(不可重復(fù)讀)。


  • REPEATABLE READ(可重復(fù)讀):InnoDB默認(rèn)采取該隔離級(jí)別,在該隔離級(jí)別下,事務(wù)的讀操作不申請(qǐng)共享鎖,但是讀取的數(shù)據(jù)是事務(wù)開(kāi)始時(shí)的快照數(shù)據(jù)(這里可以和READ COMMITTED對(duì)比來(lái)看),寫(xiě)操作申請(qǐng)排它鎖,并在事務(wù)結(jié)束后釋放,該隔離級(jí)別解決了不可重復(fù)讀的問(wèn)題,但是沒(méi)有解決幻讀的問(wèn)題。這里解釋一下幻讀,一個(gè)事務(wù)在前后兩次查詢(xún)同一范圍的數(shù)據(jù)時(shí),得到了不同的結(jié)果(由于其他事務(wù)插入或刪除了該范圍的某些數(shù)據(jù)),這就是幻讀。


  • SERIALIAZBLE(串行化):在該隔離級(jí)別下,事務(wù)的讀操作申請(qǐng)一個(gè)共享鎖,事務(wù)的寫(xiě)操作申請(qǐng)一個(gè)排它鎖。當(dāng)我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請(qǐng)求共享或排他鎖時(shí),InnoDB會(huì)給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對(duì)于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會(huì)對(duì)這個(gè)“間隙”加鎖,這種鎖機(jī)制就是所謂的間隙鎖(Next-Key鎖),通過(guò)間隙鎖可以解決幻讀的問(wèn)題。


下面列出每個(gè)隔離級(jí)別對(duì)應(yīng)存在的問(wèn)題:

隔離級(jí)別 臟讀 不可重復(fù)讀 幻讀
READ UNCOMMITED
READ COMMITTED ×
REPEATABLE READ × ×
SERIALIZABLE × × ×

打臉

我用MySQL5.7測(cè)了一下子,發(fā)現(xiàn)InnoDB 存儲(chǔ)引擎在REPEATABLE READ隔離級(jí)別下也解決了幻讀的問(wèn)題,于是上網(wǎng)查了以下,說(shuō)是原理和SERIALIAZBLE一樣,在REPEATABLE READ隔離級(jí)別也是使用next-key鎖對(duì)范圍讀操作進(jìn)行加間隙鎖,但是如果使用間隙鎖,按道理事務(wù)A范圍查詢(xún)的時(shí)候,事務(wù)B是不能進(jìn)行delete和insert操作的,測(cè)試發(fā)現(xiàn)REPEATABLE READ隔離級(jí)別下是可以的,具體原因不得而知,如果有知道的大佬請(qǐng)留言,謝謝。以上均為自己對(duì)于事務(wù)隔離級(jí)別的一些理解,一定會(huì)存在一些錯(cuò)誤,歡迎大家拿出證據(jù)板磚伺候。
如果不知道如何測(cè)試,可以參考以下鏈接:https://zhuanlan.zhihu.com/p/36060546

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容