MySQL 鎖機(jī)制全解析從鎖的分類(lèi)到并發(fā)更新是否阻塞(最新推薦)
引言
在并發(fā)場(chǎng)景下,數(shù)據(jù)庫(kù)需要解決三類(lèi)核心問(wèn)題:
- 數(shù)據(jù)一致性:不能讀到臟數(shù)據(jù)
- 并發(fā)安全:多個(gè)事務(wù)同時(shí)修改數(shù)據(jù)時(shí)不出錯(cuò)
- 性能權(quán)衡:在一致性和并發(fā)性能之間取得平衡
MySQL(準(zhǔn)確來(lái)說(shuō)是 InnoDB 存儲(chǔ)引擎)通過(guò)一整套多層次鎖機(jī)制來(lái)解決這些問(wèn)題。這些鎖并不是“隨便加的”,而是緊密?chē)@ 事務(wù)隔離級(jí)別、索引結(jié)構(gòu)、并發(fā)訪問(wèn)模式 設(shè)計(jì)出來(lái)的。
本文將從三個(gè)層次展開(kāi):
- MySQL 有哪些鎖?
- 表鎖和行鎖到底解決了什么問(wèn)題?
- 真實(shí)并發(fā)場(chǎng)景下,SQL 會(huì)不會(huì)阻塞?為什么?
一、MySQL 有哪些鎖?——三大類(lèi)鎖體系
從作用范圍來(lái)看,MySQL 的鎖可以分為三大類(lèi):
全局鎖 → 表級(jí)鎖 → 行級(jí)鎖
全局鎖(Global Lock)
1.1 什么是全局鎖?
全局鎖會(huì)鎖住整個(gè)數(shù)據(jù)庫(kù)實(shí)例,使其進(jìn)入只讀狀態(tài)。
最典型的加鎖方式是:
FLUSH TABLES WITH READ LOCK;
此時(shí):
- 所有表都只能讀
- 所有寫(xiě)操作(INSERT / UPDATE / DELETE)都會(huì)被阻塞
1.2 全局鎖的典型使用場(chǎng)景
邏輯備份
mysqldump --single-transaction ...
在早期 MySQL 版本中,為了保證備份過(guò)程中數(shù)據(jù)一致,通常需要加全局讀鎖。
1.3 全局鎖的問(wèn)題
- 整庫(kù)不可寫(xiě)
- 在線業(yè)務(wù)幾乎不可接受
現(xiàn)在更多使用 MVCC + 一致性快照,避免全局鎖
表級(jí)鎖(Table-level Lock)
表級(jí)鎖的作用范圍是 單張表,開(kāi)銷(xiāo)小,但并發(fā)能力有限。
2.1 表鎖(Table Lock)
LOCK TABLE t_order READ; LOCK TABLE t_order WRITE;
- READ:其他線程可讀,不可寫(xiě)
- WRITE:其他線程既不可讀,也不可寫(xiě)
InnoDB 一般不推薦使用顯式表鎖
2.2 元數(shù)據(jù)鎖(MDL,Metadata Lock)
MDL 是自動(dòng)加的鎖,很多人“被它坑過(guò),但不知道是它”。
- 對(duì)表進(jìn)行 CRUD → 加 MDL 讀鎖
- 對(duì)表進(jìn)行 DDL(ALTER / DROP) → 加 MDL 寫(xiě)鎖
讀寫(xiě)互斥!
-- 事務(wù) A SELECT * FROM t_order; -- 持有 MDL 讀鎖 -- 事務(wù) B ALTER TABLE t_order ADD COLUMN xxx; -- 等待
線上 DDL 阻塞業(yè)務(wù)的元兇
2.3 意向鎖(Intention Lock)
意向鎖是 InnoDB 行鎖的“前置聲明”,存在于表級(jí)別。
- 意向共享鎖(IS)
- 意向排他鎖(IX)
作用:讓表鎖與行鎖能快速判斷是否沖突
“我要鎖某幾行了,你別直接給我整個(gè)表上鎖”
行級(jí)鎖(Row-level Lock)
行鎖是 InnoDB 的核心競(jìng)爭(zhēng)力,并發(fā)性能的關(guān)鍵。
3.1 記錄鎖(Record Lock)
鎖住 某一條索引記錄
- S 鎖(共享鎖):讀
- X 鎖(排他鎖):寫(xiě)
SELECT * FROM t_order WHERE id = 10 LOCK IN SHARE MODE; UPDATE t_order SET status = 1 WHERE id = 10;
3.2 間隙鎖(Gap Lock)
鎖住的是 索引區(qū)間之間的“空隙”
- 只存在于 RR(可重復(fù)讀)隔離級(jí)別
- 目的:防止幻讀
SELECT * FROM t_order WHERE id BETWEEN 10 AND 20 FOR UPDATE;
鎖住 (10, 20) 這個(gè)區(qū)間,阻止插入新記錄
間隙鎖之間是兼容的
3.3 臨鍵鎖(Next-Key Lock)
Next-Key Lock = Record Lock + Gap Lock
- 鎖住記錄本身
- 同時(shí)鎖住前面的間隙
這是 InnoDB RR 隔離級(jí)別的默認(rèn)加鎖策略
二、表鎖和行鎖解決了什么問(wèn)題?
| 鎖類(lèi)型 | 解決的問(wèn)題 |
|---|---|
| 表鎖 | DDL 與 DML 沖突 |
| 行鎖 | 并發(fā)更新同一行 |
| 間隙鎖 | 防止幻讀 |
| 臨鍵鎖 | 范圍查詢 + 插入一致性 |
本質(zhì)目標(biāo)只有一個(gè):
在并發(fā)環(huán)境下,保證事務(wù)隔離語(yǔ)義成立
三、并發(fā)場(chǎng)景實(shí)戰(zhàn)分析:到底會(huì)不會(huì)阻塞?
場(chǎng)景 1:兩個(gè)事務(wù)同時(shí) UPDATE 同一條記錄
UPDATE t_order SET status = 1 WHERE id = 100;
會(huì)阻塞
- 第一個(gè)事務(wù)獲取 id=100 的 X 鎖
- 第二個(gè)事務(wù)只能等待
場(chǎng)景 2:更新不同主鍵的記錄
-- 事務(wù) A UPDATE t_order SET status = 1 WHERE id = 100; -- 事務(wù) B UPDATE t_order SET status = 1 WHERE id = 200;
不會(huì)阻塞
- 行鎖粒度是“記錄級(jí)”
- 主鍵索引精確定位
場(chǎng)景 3:更新主鍵范圍(存在索引)
UPDATE t_order SET status = 1 WHERE id BETWEEN 100 AND 200;
- 加的是 Next-Key Lock
- 會(huì)鎖住區(qū)間
其他事務(wù)在該區(qū)間 INSERT 會(huì)被阻塞
場(chǎng)景 4:WHERE 條件未命中索引
UPDATE t_order SET status = 1 WHERE order_no = 'xxx';
如果 order_no 沒(méi)有索引
- InnoDB 會(huì) 全表掃描
- 鎖升級(jí)為 鎖住大量記錄甚至整表
這才是線上“莫名其妙阻塞”的根源
總結(jié)
鎖不是 SQL 層決定的,而是:
SQL + 索引 + 隔離級(jí)別 + 引擎共同作用的結(jié)果
關(guān)鍵記憶點(diǎn)
- RR 隔離級(jí)別 ≠ 只有行鎖
- Next-Key Lock 是默認(rèn)策略
- 無(wú)索引 ≈ 放棄行鎖優(yōu)勢(shì)
- MDL 是 DDL 阻塞的幕后黑手
實(shí)戰(zhàn)建議
- 所有更新 SQL 必須走索引
- 范圍更新要評(píng)估間隙鎖影響
- 線上 DDL 使用 Online DDL
- 用
show engine innodb status排查鎖等待
到此這篇關(guān)于MySQL 鎖機(jī)制全解析:從鎖的分類(lèi)到并發(fā)更新是否阻塞的文章就介紹到這了,更多相關(guān)mysql 鎖機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
linux mysql忘記密碼的多種解決或Access denied for user ''root''@''local
linux mysql忘記密碼的多種解決方法。2009-07-07
SQL語(yǔ)句單引號(hào)與雙引號(hào)的使用方法
這篇文章主要介紹了SQL語(yǔ)句中單引號(hào)、雙引號(hào)的使用方法,分別講述,雖然說(shuō)的是Insert語(yǔ)句,?但是Select、Update、Delete語(yǔ)句都是一樣的,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-03-03
mysql中url時(shí)區(qū)的陷阱該如何規(guī)避詳解
最近在工作中發(fā)現(xiàn)一個(gè)問(wèn)題,是關(guān)于mysql中url時(shí)區(qū)的,發(fā)現(xiàn)這個(gè)陷阱如果大家不注意可能都會(huì)遇到,所以給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于mysql中url時(shí)區(qū)的陷阱該如何規(guī)避的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-08-08
MySQL實(shí)際項(xiàng)目中常用的 DDL 模板
本文詳細(xì)介紹了數(shù)據(jù)庫(kù)表的常見(jiàn)操作,包括創(chuàng)建帶審計(jì)字段和索引的模板、修改表結(jié)構(gòu)(如新增、刪除、修改字段)、索引管理(新增、刪除普通、唯一索引及聯(lián)合索引)、外鍵約束的新增和刪除、表結(jié)構(gòu)變更(如重命名表、設(shè)置字符集)以及刪除表,感興趣的朋友跟隨小編一起看看吧2025-12-12
MySql報(bào)錯(cuò):unblock with mysqladmin flush-hosts的解
這篇文章主要介紹了MySql報(bào)錯(cuò):unblock with mysqladmin flush-hosts的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2026-03-03

