【面試普通人VS高手系列】innoDB如何解決幻讀

跟著Mic學架構發表於2022-04-11

前天有個去快手面試的小夥伴私信我,他遇到了這樣一個問題: “InnoDB如何解決幻讀”?

這個問題確實不是很好回答,在實際應用中,很多同學幾乎都不關注資料庫的事務隔離性。

所有問題基本就是CRUD,一把梭~

那麼今天,我們來看一下 關於“InnoDB如何解決幻讀”這個問題,普通人和高手的回答!

普通人:

嗯,我印象中,幻讀是通過MVCC機制來解決的,嗯....

MVCC類似於一種樂觀鎖的機制,通過版本的方式來區分不同的併發事務,避免幻讀問題!


高手:

我會從三個方面來回答:

1、 Mysql的事務隔離級別

Mysql有四種事務隔離級別,這四種隔離級別代表當存在多個事務併發衝突時,可能出現的髒讀、不可重複讀、幻讀的問題。

其中InnoDB在RR的隔離級別下,解決了幻讀的問題。

img

2、 什麼是幻讀?

那麼, 什麼是幻讀呢?

幻讀是指在同一個事務中,前後兩次查詢相同的範圍時,得到的結果不一致

img

  • 第一個事務裡面我們執行了一個範圍查詢,這個時候滿足條件的資料只有一條
  • 第二個事務裡面,它插入了一行資料,並且提交了
  • 接著第一個事務再去查詢的時候,得到的結果比第一次查詢的結果多出來了一條資料。

所以,幻讀會帶來資料一致性問題。

3、 InnoDB如何解決幻讀的問題

InnoDB引入了間隙鎖和next-key Lock機制來解決幻讀問題,為了更清晰的說明這兩種鎖,我舉一個例子:

假設現在存在這樣一個B+ Tree的索引結構,這個結構中有四個索引元素分別是:1、4、7、10。

img

當我們通過主鍵索引查詢一條記錄,並且對這條記錄通過for update加鎖。

img

這個時候,會產生一個記錄鎖,也就是行鎖,鎖定id=1這個索引。

img

被鎖定的記錄在鎖釋放之前,其他事務無法對這條記錄做任何操作。

前面我說過對幻讀的定義: 幻讀是指在同一個事務中,前後兩次查詢相同的範圍時,得到的結果不一致!

注意,這裡強調的是範圍查詢,

也就是說,InnoDB引擎要解決幻讀問題,必須要保證一個點,就是如果一個事務通過這樣一條語句進行鎖定時。

img

另外一個事務再執行這樣一條insert語句,需要被阻塞,直到前面獲得鎖的事務釋放。

img

所以,在InnoDB中設計了一種間隙鎖,它的主要功能是鎖定一段範圍內的索引記錄

img

當對查詢範圍id>4 and id <7加鎖的時候,會針對B+樹中(4,7)這個開區間範圍的索引加間隙鎖。

意味著在這種情況下,其他事務對這個區間的資料進行插入、更新、刪除都會被鎖住。

但是,還有另外一種情況,比如像這樣

img

這條查詢語句是針對id>4這個條件加鎖,那麼它需要鎖定多個索引區間,所以在這種情況下InnoDB引入了next-key Lock機制。

next-key Lock相當於間隙鎖和記錄鎖的合集,記錄鎖鎖定存在的記錄行,間隙鎖鎖住記錄行之間的間隙,而next-key Lock鎖住的是兩者之和。

img

每個資料行上的非唯一索引列上都會存在一把next-key lock,當某個事務持有該資料行的next-key lock時,會鎖住一段左開右閉區間的資料。

因此,當通過id>4這樣一種範圍查詢加鎖時,會加next-key Lock,鎖定的區間範圍是:(4, 7] , (7,10],(10,+∞]

img

間隙鎖和next-key Lock的區別在於加鎖的範圍,間隙鎖只鎖定兩個索引之間的引用間隙,而next-key Lock會鎖定多個索引區間,它包含記錄鎖和間隙鎖。

當我們使用了範圍查詢,不僅僅命中了Record記錄,還包含了Gap間隙,在這種情況下我們使用的就是臨鍵鎖,它是MySQL裡面預設的行鎖演算法。

4 、總結

雖然InnoDB中通過間隙鎖的方式解決了幻讀問題,但是加鎖之後一定會影響到併發效能,因此,如果對效能要求較高的業務場景中,可以把隔離級別設定成RC,這個級別中不存在間隙鎖。

以上就是我對於innoDB如何解決幻讀問題的理解!


總結:

通過這個面試題可以發現,大廠面試對於基本功的考察還是比較嚴格的。

不過,不管是為了應付面試,還是為以後的職業規劃做鋪墊, 技術能力的高低都是你在這個行業的核心競爭力。

我是Mic,一個工作了14年的Java程式設計師,我們們下篇文章再見。

相關文章