1. 程式人生 > >MySQL InnoDB鎖機制之Gap Lock、Next-Key Lock、Record Lock解析

MySQL InnoDB鎖機制之Gap Lock、Next-Key Lock、Record Lock解析

分享圖片 nbsp 級別 rate efault 原因 大於 記錄鎖 html

MySQL InnoDB支持三種行鎖定方式:

l 行鎖(Record Lock):鎖直接加在索引記錄上面,鎖住的是key。

l 間隙鎖(Gap Lock):鎖定索引記錄間隙,確保索引記錄的間隙不變。間隙鎖是針對事務隔離級別為可重復讀或以上級別而已的。

l Next-Key Lock :行鎖和間隙鎖組合起來就叫Next-Key Lock。

默認情況下,InnoDB工作在可重復讀隔離級別下,並且會以Next-Key Lock的方式對數據行進行加鎖,這樣可以有效防止幻讀的發生。Next-Key Lock是行鎖和間隙鎖的組合,當InnoDB掃描索引記錄的時候,會首先對索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙加上間隙鎖(Gap Lock)。加上間隙鎖之後,其他事務就不能在這個間隙修改或者插入記錄。

Gap Lock在InnoDB的唯一作用就是防止其他事務的插入操作,以此防止幻讀的發生。

1、 行鎖(Record Lock)

行鎖鎖定的是索引記錄,而不是行數據,也就是說鎖定的是key。

2、 間隙鎖(Gap Lock)

例如:

create table test(id int,v1 int,v2 int,primary key(id),key `idx_v1`(`v1`))Engine=InnoDB DEFAULT CHARSET=UTF8;

該表的記錄如下:

+----+------+------+

| id | v1 | v2 |

+----+------+------+

| 1 | 1 | 0 |

| 2 | 3 | 1 |

| 3 | 4 | 2 |

| 5 | 5 | 3 |

| 7 | 7 | 4 |

| 10 | 9 | 5 |

間隙鎖(Gap Lock)一般是針對非唯一索引而言的,test表中的v1(非唯一索引)字段值可以劃分的區間為:

(-∞,1)

(1,3)

(3,4)

(4,5)

(5,7)

(7,9)

(9, +∞)

假如要更新v1=7的數據行,那麽此時會在索引idx_v1對應的值,也就是v1的值上加間隙鎖,鎖定的區間是(5,7)和(7,9)。同時找到v1=7的數據行的主鍵索引和非唯一索引,對key加上鎖。

3、 後碼鎖(Next-Key Lock)

記錄鎖和間隙鎖的結合,對於InnoDB中,更新非唯一索引對應的記錄(在這裏來說是更新v1字段的值),會加上Next-Key Lock。如果更新記錄為空,就不能加記錄鎖,只能加間隙鎖。

舉個例子(事務隔離級別為MySQL默認的可重復讀)

技術分享圖片

為什麽TRANSACTION 2的insert操作會被阻塞,產生等待呢?這是因為TRANSACTION 2插入的v1值為6在TRANSACTION 1的鎖定區間(5,9)內。而TRANSACTION 1插入的v1值不在TRANSACTION 2的鎖定區間(5,7)內,故可以成功插入。不僅僅insert操作, update操作也一樣會被鎖住,從而鎖等待超時。

4、 鎖選擇

1)、如果更新條件沒有走索引,例如執行”update from t1 set v2=0 where v2=5;” ,此時會進行全表掃描,掃表的時候,要阻止其他任何的更新操作,所以上升為表鎖。

2)、如果更新條件為索引字段,但是並非唯一索引(包括主鍵索引),例如執行“update from t1 set v2=0 where v1=9;” 那麽此時更新會使用Next-Key Lock。使用Next-Key Lock的原因:

a)、首先要保證在符合條件的記錄上加上排他鎖,會鎖定當前非唯一索引和對應的主鍵索引的值;

b)、還要保證鎖定的區間不能插入新的數據。

3)、如果更新條件為唯一索引,則使用Record Lock(記錄鎖)。

InnoDB根據唯一索引,找到相應記錄,將主鍵索引值和唯一索引值加上記錄鎖。但不使用Gap Lock(間隙鎖)。

5、 間隙鎖(Gap Lock)

加後碼鎖的時候,並沒有鎖住間隙兩端的記錄(這裏的兩端分別是5,9和5,7),那麽兩端的記錄是可以更新的,但是如果更新兩端的記錄會影響到間隙鎖,那麽操作會被掛起,等待間隙鎖釋放。

技術分享圖片

看以下演示:

技術分享圖片

技術分享圖片

為什麽在左側值為4,右側值為7的時候,有時候操作會被掛起,有時候操作不會掛起呢?解釋如下:

技術分享圖片

當插入左側值的時候,即插入v1=4的時候,要求插入的id值小於id=3的範圍。當v1=4的記錄有多條的時候,插入的id值要小於其中的最大id值。則可以成功插入;

當插入右側值的時候,即插入v1=7的時候,要求插入的id值要大於id=7的範圍。當v1=7的記錄有多條的時候,插入的id值要大於其中的最小id值。則可以成功插入。

MySQL InnoDB鎖機制之Gap Lock、Next-Key Lock、Record Lock解析