MySQL 的全局鎖、表鎖和行鎖



唯一索引等值查詢
當查詢的記錄是存在的,在用「唯一索引進行等值查詢」時,next-key lock 會退化成「記錄鎖」。
當查詢的記錄是不存在的,在用「唯一索引進行等值查詢」時,next-key lock 會退化成「間隙鎖」。
先看看記錄是存在的。

加鎖的基本單位是 next-key lock,因此會話1的加鎖范圍是(8, 16];
但是由于是用唯一索引進行等值查詢,且查詢的記錄存在,所以 next-key lock 退化成記錄鎖,因此最終加鎖的范圍是 id = 16 這一行。
接下來,看看記錄不存在的情況

加鎖的基本單位是 next-key lock,因此主鍵索引 id 的加鎖范圍是(8, 16];
但是由于查詢記錄不存在,next-key lock 退化成間隙鎖,因此最終加鎖的范圍是 (8,16)。
唯一索引范圍查詢
select * from t_test where id=8 for update;
select * from t_test where id>=8 and id<9 for update;

最開始要找的第一行是 id = 8,因此 next-key lock(4,8],但是由于 id 是唯一索引,且該記錄是存在的,因此會退化成記錄鎖,也就是只會對 id = 8 這一行加鎖;
由于是范圍查找,就會繼續(xù)往后找存在的記錄,也就是會找到 id = 16 這一行停下來,然后加 next-key lock (8, 16],但由于 id = 16 不滿足 id < 9,所以會退化成間隙鎖,加鎖范圍變?yōu)?(8, 16)。
非唯一索引等值查詢
當查詢的記錄存在時,除了會加 next-key lock 外,還額外加間隙鎖,也就是會加兩把鎖。
當查詢的記錄不存在時,只會加 next-key lock,然后會退化為間隙鎖,也就是只會加一把鎖。
我們先來看看查詢的值存在的情況。

先會對普通索引 b 加上 next-key lock,范圍是(4,8];
然后因為是非唯一索引,且查詢的記錄是存在的,所以還會加上間隙鎖,規(guī)則是向下遍歷到第一個不符合條件的值才能停止,因此間隙鎖的范圍是(8,16)。
接下來,我們看看查詢的值不存在的情況

先會對普通索引 b 加上 next-key lock,范圍是(8,16];
但是由于查詢的記錄是不存在的,所以不會再額外加個間隙鎖,但是 next-key lock 會退化為間隙鎖,最終加鎖范圍是 (8,16)。
非唯一索引范圍查詢

最開始要找的第一行是 b = 8,因此 next-key lock(4,8],但是由于 b 不是唯一索引,并不會退化成記錄鎖。
但是由于是范圍查找,就會繼續(xù)往后找存在的記錄,也就是會找到 b = 16 這一行停下來,然后加 next-key lock (8, 16],因為是普通索引查詢,所以并不會退化成間隙鎖。
總結(jié)
當查詢的記錄是存在的,next-key lock 會退化成「記錄鎖」。
當查詢的記錄是不存在的,next-key lock 會退化成「間隙鎖」。
當查詢的記錄存在時,除了會加 next-key lock 外,還額外加間隙鎖,也就是會加兩把鎖。
當查詢的記錄不存在時,只會加 next-key lock,然后會退化為間隙鎖,也就是只會加一把鎖。
唯一索引在滿足一些條件的時候,next-key lock 退化為間隙鎖和記錄鎖。
非唯一索引范圍查詢,next-key lock 不會退化為間隙鎖和記錄鎖。
