MySQL InnoDB鎖機(jī)制之從Record到Next-Key的使用解讀
在真實業(yè)務(wù)中,你遇到的大多數(shù) MySQL 性能問題、死鎖問題,幾乎都與“鎖”有關(guān)。但很多工程師對鎖的理解停留在碎片層面:
知道“行鎖”“間隙鎖”“next-key-lock”,但不知道 SQL 是如何觸發(fā)這些鎖的、鎖到底鎖在哪里、為什么會鎖這么多。
這一篇文章,我會用工程化思維,帶你一次性理解 InnoDB 鎖機(jī)制的全景圖。
看完以后,你將具備:
- ? 能看懂鎖的真實作用
- ? 能從 SQL 推斷出鎖范圍
- ? 能解釋死鎖發(fā)生原因
- ? 能在面試中條理清晰地講出鎖機(jī)制
一、為什么 InnoDB 的鎖機(jī)制這么復(fù)雜?
MySQL 采用 MVCC + 鎖 實現(xiàn)事務(wù)隔離,其中最關(guān)鍵的隔離級別是:
- RC:讀已提交
- RR:可重復(fù)讀(默認(rèn))
RR 是企業(yè)最常見的隔離級別,它要解決“幻讀”問題。
于是有了三個鎖:
- 記錄鎖(Record Lock)
- 間隙鎖(Gap Lock)
- Next-Key Lock(Record + Gap)
所有復(fù)雜問題都來自這個組合。
二、InnoDB 的三種核心鎖(理解它們的作用和觸發(fā)條件)
Record Lock:真實行上的鎖
- 鎖的對象:一條真實存在的記錄
- 觸發(fā)場景:精確命中唯一索引
例如:
SELECT * FROM user WHERE id = 10 FOR UPDATE;
只鎖 (10] —— 單條記錄。
特點:不會鎖間隙,因此不會阻止插入。
Gap Lock:只鎖“間隙”,不鎖數(shù)據(jù)
作用:阻止“間隙內(nèi)插入新數(shù)據(jù)”,防止幻讀。
例如:
索引中已有值:
10 --- 20 --- 30
SQL:
SELECT * FROM user WHERE age > 20 FOR UPDATE;
Gap Lock 會鎖?。?/p>
(20, 30) (30, +∞)
重點:Gap Lock 不鎖記錄,只鎖區(qū)間。
Next-Key Lock:Record + Gap 的組合鎖
RR 下范圍查詢的默認(rèn)鎖模式:
(prev_key, record_key]
例如:(假設(shè)索引有 10、20、30)
SELECT * FROM t WHERE age BETWEEN 15 AND 25 FOR UPDATE;
鎖住的區(qū)間:
(10,20] (20,30]
作用:
- ? 鎖住命中的記錄
- ? 鎖住記錄前的 gap → 阻止插入
這就是為什么 RR 隔離級別能規(guī)避幻讀。
三、鎖到底由哪些 SQL 觸發(fā)?
“ SQL → 鎖類型” 映射表:
| SQL 場景 | 索引情況 | 鎖類型 | 原因 |
|---|---|---|---|
| WHERE id = ?(唯一鍵) | 精確命中 | Record Lock | 不需要鎖 gap |
| WHERE id = ?(普通索引) | 精確匹配,但非唯一 | Next-Key Lock | 防止幻讀 |
| WHERE age > ? / < ? | 范圍掃描 | Next-Key Lock | 必須鎖 gap |
| BETWEEN 范圍查詢 | 范圍掃描 | Next-Key Lock | 防止插入 |
| 無索引過濾 | 全表掃描 | 大量 Record Lock | 每條記錄都會被鎖 |
| LIKE '%abc' | 無法走索引 | 表鎖風(fēng)險 | 全表掃描 |
一句話總結(jié):
- 能精確鎖住記錄 → Record Lock
- 需要范圍掃描 → Next-Key Lock
- 范圍掃描一定會鎖 gap → Gap Lock
四、鎖具體加在什么區(qū)間?
假設(shè)索引中有如下值:
10 ---- 20 ---- 30 ---- 40
來看不同 SQL 加的鎖??
WHERE id = 20 FOR UPDATE
鎖:
(10, 20]
但如果字段是主鍵/唯一鍵,會優(yōu)化成:
[20]
WHERE id > 20 FOR UPDATE
鎖:
(20,30) (30,40) (40,+∞)
WHERE id BETWEEN 15 AND 35 FOR UPDATE
鎖:
(10,20] (20,30] (30,40]
無索引條件
SELECT * FROM user WHERE name='xxx' FOR UPDATE;
鎖住所有記錄:
[10], [20], [30], [40]
→ 大量鎖沖突發(fā)生的根源。
五、總結(jié)
- InnoDB 的鎖永遠(yuǎn)基于索引。
- 無法精確匹配記錄,就會使用 Next-Key Lock。
- 范圍查詢一定會帶 gap 鎖。
掌握這三點后,死鎖、鎖等待、幻讀問題都能一眼看穿。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mysql安裝 Navicat 出現(xiàn)1044/1045錯誤的解決方法
Navicat 出現(xiàn)1044/1045錯誤是網(wǎng)友們一直頭疼的問題,本文以此進(jìn)行詳細(xì)介紹,需要了解的朋友可以參考下2012-12-12
SQL Server 2005 安裝遇到的錯誤提示和解決方法
在安裝SQL Server 2005時有時會出現(xiàn)意想不到的問題,如IIS,性能計數(shù)器,OWC11,無法配置外圍應(yīng)用的問題,下面筆者分享一下在安裝SQL Server 2005時常見問題解決方法2014-01-01
MySQL實現(xiàn)創(chuàng)建存儲過程并循環(huán)添加記錄的方法
這篇文章主要介紹了MySQL實現(xiàn)創(chuàng)建存儲過程并循環(huán)添加記錄的方法,涉及基本的mysql存儲過程創(chuàng)建、調(diào)用相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
MySQL多表關(guān)聯(lián)on和where速度對比實測看誰更快
這篇文章主要介紹了MySQL多表關(guān)聯(lián)on和where速度對比實測看誰更快問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03

