MySQL間隙鎖與排他鎖的區(qū)別全解析
【MySQL】間隙鎖 與 排他鎖 的區(qū)別
這是一個(gè)非常核心的數(shù)據(jù)庫(kù)鎖機(jī)制問(wèn)題。簡(jiǎn)單來(lái)說(shuō):排他鎖(X鎖)是"鎖什么",間隙鎖(Gap Lock)是"鎖哪里"。
?? 核心區(qū)別對(duì)比表
| 特性 | 排他鎖 (X鎖) | 間隙鎖 (Gap Lock) |
|---|---|---|
| 鎖的類型 | 鎖類型 - 定義鎖的"權(quán)限" | 鎖范圍 - 定義鎖的"位置" |
| 作用對(duì)象 | 已存在的數(shù)據(jù)行 | 數(shù)據(jù)行之間的間隙 |
| 兼容性 | 與任何其他鎖都不兼容 | 與其他間隙鎖兼容,但與插入意向鎖沖突 |
| 主要目的 | 防止其他事務(wù)讀寫數(shù)據(jù) | 防止其他事務(wù)在范圍內(nèi)插入新數(shù)據(jù) |
| 可見范圍 | 行記錄本身 | 索引記錄之間的"空隙" |
| 何時(shí)使用 | UPDATE、DELETE、SELECT…FOR UPDATE | 可重復(fù)讀隔離級(jí)別下的范圍查詢 |
?? 詳細(xì)解釋
1. 排他鎖(X鎖)- 行級(jí)鎖
-- 示例:對(duì)uid=8的行加排他鎖 SELECT * FROM student WHERE uid = 8 FOR UPDATE; -- 或 UPDATE student SET age = 60 WHERE uid = 8;
特點(diǎn):
- 鎖定具體的數(shù)據(jù)行
- 其他事務(wù)不能讀?。⊿ELECT…FOR UPDATE)也不能修改(UPDATE/DELETE)該行
- 可以看作"寫鎖"
2. 間隙鎖(Gap Lock)- 范圍鎖
-- 示例:鎖定uid在(5, 10)之間的所有間隙 SELECT * FROM student WHERE uid BETWEEN 6 AND 9 FOR UPDATE; -- 或 SELECT * FROM student WHERE uid > 5 AND uid < 10 FOR UPDATE;
假設(shè)你的表數(shù)據(jù):
uid: 1, 2, 3, 4, 5, 7, 8, 10, 11
間隙包括:(-∞,1), (1,2), (2,3), …, (5,7), (7,8), (8,10), (10,11), (11,+∞)
特點(diǎn):
- 鎖定索引記錄之間的空隙,而不是記錄本身
- 防止其他事務(wù)在范圍內(nèi)插入新數(shù)據(jù)
- 只在可重復(fù)讀(REPEATABLE-READ) 隔離級(jí)別下有效
?? 實(shí)際工作場(chǎng)景
場(chǎng)景1:防止幻讀(Phantom Read)
-- 事務(wù)一
BEGIN;
SELECT * FROM student WHERE age BETWEEN 20 AND 30 FOR UPDATE;
-- 鎖定所有age在20-30之間的間隙
-- 事務(wù)二嘗試插入age=25的新記錄(會(huì)被阻塞)
INSERT INTO student (name, age, sex) VALUES ('new_student', 25, 'M');場(chǎng)景2:組合使用 - 臨鍵鎖(Next-Key Lock)
MySQL 實(shí)際上經(jīng)常使用 **臨鍵鎖 = 記錄鎖 + 間隙鎖** -- 鎖定uid=8的行及其前后的間隙 SELECT * FROM student WHERE uid = 8 FOR UPDATE; -- 實(shí)際鎖定:(7, 8] 和 (8, 10)
?? 重要注意事項(xiàng)
1. 間隙鎖只作用于非唯一索引
-- 如果name有唯一索引,不會(huì)加間隙鎖 SELECT * FROM student WHERE name = 'bbbb' FOR UPDATE; -- 只對(duì)'bbbb'這一行加排他鎖 -- 如果name沒(méi)有索引或不是唯一索引,可能會(huì)鎖全表間隙 SELECT * FROM student WHERE name LIKE 'b%' FOR UPDATE;
2. 查看鎖信息
-- 查看當(dāng)前的鎖(MySQL 8.0+)
SELECT
engine_transaction_id as trx_id,
lock_type,
lock_mode,
lock_data,
index_name
FROM performance_schema.data_locks
WHERE object_name = 'student';3. 死鎖風(fēng)險(xiǎn)
間隙鎖容易導(dǎo)致死鎖,特別是并發(fā)插入時(shí):
-- 事務(wù)A BEGIN; SELECT * FROM student WHERE uid = 15 FOR UPDATE; -- 間隙鎖(10, +∞) -- 事務(wù)B BEGIN; SELECT * FROM student WHERE uid = 16 FOR UPDATE; -- 間隙鎖(10, +∞) -- 事務(wù)A INSERT INTO student (uid, name) VALUES (15, 'test'); -- 等待B -- 事務(wù)B INSERT INTO student (uid, name) VALUES (16, 'test'); -- 等待A → 死鎖!
?? 性能影響與優(yōu)化
| 情況 | 影響 | 解決方案 |
|---|---|---|
| 全表間隙鎖 | 鎖住所有間隙,并發(fā)極差 | 使用唯一索引查詢 |
| 范圍查詢 | 鎖住大范圍間隙 | 縮小查詢范圍 |
| 批量操作 | 可能鎖大量間隙 | 分批次操作 |
| 高并發(fā)插入 | 容易死鎖 | 降低隔離級(jí)別為RC |
?? 最佳實(shí)踐建議
明確使用場(chǎng)景:
需要防止幻讀 → 使用間隙鎖(RR隔離級(jí)別)
只需要防止數(shù)據(jù)修改 → 使用行級(jí)排他鎖
索引設(shè)計(jì):
-- 好的設(shè)計(jì):使用唯一索引避免不必要的間隙鎖 CREATE UNIQUE INDEX idx_uid ON student(uid); -- 查詢時(shí)使用唯一索引 SELECT * FROM student WHERE uid = 8 FOR UPDATE; -- 只鎖一行
隔離級(jí)別選擇:
-- 如果不需要防止幻讀,使用讀已提交 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 此時(shí)不會(huì)加間隙鎖
避免長(zhǎng)事務(wù):
-- 盡快提交事務(wù),減少鎖持有時(shí)間 BEGIN; -- 立即執(zhí)行需要加鎖的操作 SELECT ... FOR UPDATE; UPDATE ...; -- 盡快提交 COMMIT;
?? 總結(jié)要點(diǎn)
- 排他鎖是"行鎖" - 鎖已存在的數(shù)據(jù)
- 間隙鎖是"范圍鎖" - 鎖不存在的間隙
- MySQL 默認(rèn)使用 臨鍵鎖(行鎖+間隙鎖)
- 間隙鎖主要在 RR隔離級(jí)別 防止幻讀
- 設(shè)計(jì)好索引可以大大減少不必要的間隙鎖
在你的學(xué)生表例子中,如果 uid 是唯一索引,SELECT ... WHERE uid=8 FOR UPDATE 只會(huì)加行鎖。如果 name 不是唯一索引,相同的查詢可能會(huì)加間隙鎖。
到此這篇關(guān)于MySQL間隙鎖與排他鎖的區(qū)別全解析的文章就介紹到這了,更多相關(guān)mysql間隙鎖與排他鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL?8.0.29?安裝配置方法圖文教程(windows?zip版)
這篇文章主要為大家詳細(xì)介紹了windows?zip版MySQL?8.0.29?安裝配置方法圖文教程,文中安裝步驟介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
MySQL5.6使用mysqldump數(shù)據(jù)備份的實(shí)現(xiàn)
本文主要介紹了MySQL5.6使用mysqldump數(shù)據(jù)備份的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2026-03-03
MySQL?添加索引5種方式示例詳解(實(shí)用sql代碼)
在MySQL數(shù)據(jù)庫(kù)中添加索引可以幫助提高查詢性能,尤其是在數(shù)據(jù)量大的表中,下面給大家分享MySQL添加索引5種方式示例詳解(實(shí)用sql代碼),感興趣的朋友一起看看吧2025-05-05
設(shè)置和修改MySQL的root密碼的詳細(xì)教程
在 MySQL 數(shù)據(jù)庫(kù)的使用過(guò)程中,設(shè)置和修改 root 用戶的密碼是一項(xiàng)基本且重要的操作,root 用戶擁有數(shù)據(jù)庫(kù)的最高權(quán)限,因此確保其密碼的安全性至關(guān)重要,本文將詳細(xì)介紹在不同操作系統(tǒng)環(huán)境下設(shè)置和修改 MySQL root 密碼的具體步驟,幫助你輕松掌握這一關(guān)鍵技能2025-05-05
MySQL需要根據(jù)特定順序排序的實(shí)現(xiàn)方法
在MySQL中,我們可以通過(guò)指定順序排序來(lái)在查詢結(jié)果中控制數(shù)據(jù)的排列順序,這種排序方式是非常有用的,本文就來(lái)介紹一下,感興趣的可以了解一下2023-11-11

