MySQL?中的行鎖(Record?Lock)?和?間隙鎖(Gap?Lock)詳解
1. 行鎖(Record Lock)
定義
- Record Lock 是 InnoDB 在事務中對索引記錄加的鎖,用于保護某一行數(shù)據(jù)不被其他事務修改。
- 它是基于索引的鎖,如果沒有索引,InnoDB 會退化為表鎖。
作用
- 防止其他事務修改或刪除當前事務正在處理的行。
- 保證事務的隔離性(尤其是
REPEATABLE READ和SERIALIZABLE隔離級別)。
觸發(fā)場景
- 常見于
SELECT ... FOR UPDATE或UPDATE、DELETE操作。 - 必須通過索引定位行,否則會鎖住更多數(shù)據(jù)(甚至全表)。
例子
假設有表:
CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50), age INT ) ENGINE=InnoDB;
事務 A:
BEGIN; SELECT * FROM user WHERE id=5 FOR UPDATE;
- InnoDB 會在
id=5這一行的索引記錄上加 Record Lock。 - 事務 B 如果執(zhí)行:
UPDATE user SET age=30 WHERE id=5;
會被阻塞,直到事務 A 提交或回滾。
2. 間隙鎖(Gap Lock)
定義
- Gap Lock 是 InnoDB 在事務中對索引記錄之間的間隙加的鎖。
- 它鎖住的是索引之間的空隙,而不是具體的行。
- 主要用于防止幻讀(Phantom Read)。
作用
- 阻止其他事務在某個索引范圍內(nèi)插入新記錄。
- 常見于范圍查詢(
BETWEEN、>、<)或REPEATABLE READ隔離級別下的SELECT ... FOR UPDATE。
觸發(fā)場景
- 范圍查詢并加鎖時(
FOR UPDATE或LOCK IN SHARE MODE)。 - 在
REPEATABLE READ下,InnoDB 會自動加 Gap Lock 來防止幻讀。
例子
假設表中有數(shù)據(jù):
id: 1, 5, 10
事務 A:
BEGIN; SELECT * FROM user WHERE id BETWEEN 5 AND 10 FOR UPDATE;
- InnoDB 會對
id=5和id=10加 Record Lock。 - 同時會對
(5,10)之間的空隙加 Gap Lock。 - 事務 B 如果執(zhí)行:
INSERT INTO user VALUES (7, 'Tom', 25);
會被阻塞,因為 (5,10) 的間隙被鎖住。
3. 區(qū)別總結
| 鎖類型 | 鎖住對象 | 作用 | 常見場景 |
|---|---|---|---|
| Record Lock | 某一行的索引記錄 | 防止該行被修改或刪除 | 精確匹配索引的 UPDATE、DELETE、SELECT ... FOR UPDATE |
| Gap Lock | 索引記錄之間的空隙 | 防止在范圍內(nèi)插入新記錄 | 范圍查詢加鎖,防止幻讀 |
? 總結:
- Record Lock:鎖住已有的行,防止修改或刪除。
- Gap Lock:鎖住索引間的空隙,防止插入新行。
- 兩者經(jīng)常一起出現(xiàn),比如范圍查詢時會同時鎖住已有行和間隙,這種組合鎖叫 Next-Key Lock。
BEGIN; SELECT * FROM user WHERE id BETWEEN a AND b FOR UPDATE;
如果a和b距離很大是否直接鎖住a和b中間所有行
是的,
在 InnoDB 的 REPEATABLE READ 隔離級別下,執(zhí)行
BEGIN; SELECT * FROM user WHERE id BETWEEN a AND b FOR UPDATE;
會觸發(fā) Next-Key Lock(Record Lock + Gap Lock 的組合),它會鎖住范圍內(nèi)所有匹配的行,并且鎖住這些行之間的間隙,防止其他事務在這個范圍內(nèi)插入新數(shù)據(jù)。
1. 鎖定范圍的規(guī)則
假設 id 是主鍵索引,表中數(shù)據(jù)如下:
id: 1, 5, 10, 20, 50, 100
如果執(zhí)行:
SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;
InnoDB 會:
- 對
id=5、id=10、id=20、id=50加 Record Lock(行鎖) - 對
(5,10)、(10,20)、(20,50)這些間隙加 Gap Lock - 還會對
(50, 下一條記錄)的間隙加鎖(防止插入 51、60 等)
2. 如果 a 和 b 很遠
如果 a=5,b=1000000,而表中有很多行:
- 是的,InnoDB 會鎖住
id=5到id=1000000范圍內(nèi)所有匹配的行和它們之間的間隙。 - 這意味著這個范圍內(nèi)的更新、刪除、插入都會被阻塞,直到事務提交或回滾。
- 如果范圍特別大,可能會造成大范圍鎖定,嚴重影響并發(fā)性能。
3. 注意事項
- 基于索引:行鎖和間隙鎖都是基于索引的,如果
id沒有索引,InnoDB 會退化成表鎖,鎖住整張表。 - 范圍越大,鎖的行和間隙越多,并發(fā)沖突風險越高。
- 如果只想鎖住已存在的行而不鎖間隙,可以使用
READ COMMITTED隔離級別(Gap Lock 不會生效)。
4. 直觀示意
假設:
id: 1, 5, 10, 20, 50, 100
執(zhí)行:
SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;
鎖定范圍:
[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====
- [x] 表示 Record Lock(行鎖)
- (gap) 表示 Gap Lock(間隙鎖)
我建議,如果你的 a 和 b 之間范圍特別大,可以考慮:
- 拆分查詢,減少一次性鎖定的范圍
- 使用更精確的條件,避免鎖住無關數(shù)據(jù)
- 降低隔離級別(如
READ COMMITTED)減少 Gap Lock
為什么5前面沒有被鎖住?
在執(zhí)行
BEGIN; SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;
的時候,為什么 id=5 前面的間隙(比如 (1,5))沒有被鎖???
核心原因:鎖定范圍是由查詢條件決定的
InnoDB 的 Next-Key Lock(行鎖 + 間隙鎖)只會鎖住滿足查詢條件的記錄以及這些記錄之間的間隙。
- 查詢條件是
id BETWEEN 5 AND 50 - 范圍的起點是
id=5 - 所以它不會去鎖
(1,5)這個間隙,因為這個間隙里的值(比如 2、3、4)不滿足條件,不會影響當前事務的結果集。
鎖定范圍的精確規(guī)則
在 REPEATABLE READ 隔離級別下:
- Record Lock:鎖住滿足條件的記錄(這里是
id=5, 10, 20, 50)。 - Gap Lock:鎖住這些記錄之間的間隙,以及最后一條記錄到下一條記錄之間的間隙。
- 不鎖條件范圍外的間隙,因為它們不會導致幻讀。
例子對比
假設表數(shù)據(jù):
id: 1, 5, 10, 20, 50, 100
查詢:
SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;
鎖定范圍:
[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====
[x]= Record Lock(gap)= Gap Lock(1,5)不鎖,因為不在條件范圍內(nèi)。
如果是:
SELECT * FROM user WHERE id >= 5 FOR UPDATE;
鎖定范圍:
[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====[100]====(gap)====
- 依然不會鎖
(1,5),因為條件是>=5。
如果是:
SELECT * FROM user WHERE id > 1 FOR UPDATE;
鎖定范圍:
(1,5)====[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====[100]====(gap)====
- 這時
(1,5)會被鎖,因為它在條件范圍內(nèi)(>1)。
? 總結:
- InnoDB 只鎖條件范圍內(nèi)的記錄和間隙,不會鎖條件范圍外的間隙。
BETWEEN 5 AND 50的起點是 5,所以 5 前面的間隙不會被鎖。- 如果條件包含更小的值(比如
>1),那么 5 前面的間隙就會被鎖。
到此這篇關于MySQL 中的行鎖(Record Lock) 和 間隙鎖(Gap Lock)詳解的文章就介紹到這了,更多相關mysql行鎖和間隙鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
如何使用mysqladmin獲取一個mysql實例當前的TPS和QPS
這篇文章主要介紹了如何使用mysqladmin這個工具來獲取一個mysql實例當前的TPS和QPS,幫助大家更好的管理數(shù)據(jù)庫,感興趣的朋友可以了解下2020-11-11

