前置知识: MySQL

锁分类

00:00
1 min Advanced 2026/6/14

MySQL InnoDB锁分类:全局锁、表级锁、元数据锁、意向锁、行锁、间隙锁、临键锁、插入意向锁

1. 锁分类总览

MySQL 锁
├── 全局锁
├── 表级锁
│   ├── 表锁(READ/WRITE)
│   ├── 元数据锁(MDL)
│   └── 意向锁(IS/IX)
├── 行级锁
│   ├── 记录锁(Record Lock)
│   ├── 间隙锁(Gap Lock)
│   ├── 临键锁(Next-Key Lock)
│   └── 插入意向锁(Insert Intention Lock)
└── 自增锁(AUTO-INC Lock)

2. 全局锁

-- 全局读锁(用于备份)
FLUSH TABLES WITH READ LOCK;

-- 备份
mysqldump --single-transaction mydb > backup.sql

-- 释放
UNLOCK TABLES;

3. 表级锁

3.1 表锁

LOCK TABLES employees READ;       -- 读锁
LOCK TABLES employees WRITE;      -- 写锁
UNLOCK TABLES;

3.2 元数据锁(MDL)

-- MDL 自动获取,防止 DDL 与 DML 冲突
-- SELECT → MDL 读锁
-- ALTER → MDL 写锁

-- 长事务阻塞 DDL
-- 事务A: BEGIN; SELECT * FROM t;  -- 持有 MDL 读锁
-- 事务B: ALTER TABLE t ADD COLUMN ...;  -- 等待 MDL 写锁
-- 事务C: SELECT * FROM t;  -- 等待事务B的 MDL 写锁!

-- 查看MDL等待
SELECT * FROM performance_schema.metadata_locks;

3.3 意向锁

-- 行级锁的前置声明,快速检测表级锁冲突
-- IS:打算加行级S锁
-- IX:打算加行级X锁

-- 兼容性:
-- IS-IS , IS-IX , IS-S , IS-X
-- IX-IX , IX-S , IX-X

4. 行级锁

4.1 记录锁(Record Lock)

-- 锁定索引记录
SELECT * FROM t WHERE id = 5 FOR UPDATE;
-- 锁定 id=5 的索引记录

4.2 间隙锁(Gap Lock)

-- 锁定索引记录之间的间隙
SELECT * FROM t WHERE id BETWEEN 5 AND 10 FOR UPDATE;
-- 锁定 (5, 10) 间隙,阻止插入 id=6,7,8,9

-- 间隙锁之间不冲突
-- 间隙锁与插入意向锁冲突

4.3 临键锁(Next-Key Lock)

-- 记录锁 + 间隙锁
-- InnoDB 在 REPEATABLE READ 下的默认行锁算法

-- 退化为记录锁:唯一索引等值查询且记录存在
SELECT * FROM t WHERE id = 5 FOR UPDATE;  -- id 是主键,存在
-- 只锁 id=5 行

-- 退化为间隙锁:唯一索引等值查询但记录不存在
SELECT * FROM t WHERE id = 5 FOR UPDATE;  -- id=5 不存在
-- 锁 (prev, next) 间隙

4.4 插入意向锁

-- INSERT 操作在插入前获取插入意向锁
-- 是一种特殊的间隙锁,不阻止其他插入意向锁
-- 只与间隙锁冲突

-- 多个事务向同一间隙的不同位置插入不冲突
INSERT INTO t VALUES (6, ...);  -- 事务A
INSERT INTO t VALUES (7, ...);  -- 事务B
-- 不冲突

5. 自增锁

-- AUTO-INC 锁模式
-- innodb_autoinc_lock_mode = 0:传统模式(每次INSERT加表级锁)
-- innodb_autoinc_lock_mode = 1:连续模式(批量INSERT加锁,单行轻量锁)
-- innodb_autoinc_lock_mode = 2:交叉模式(无锁,最高并发,主从不安全)

SET GLOBAL innodb_autoinc_lock_mode = 2;

6. 查看锁信息

-- MySQL 8.0+
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;

-- 查看锁等待
SELECT
    waiting.pid AS waiting_pid,
    blocking.pid AS blocking_pid,
    waiting.sql_text AS waiting_query,
    blocking.sql_text AS blocking_query
FROM performance_schema.data_lock_waits w
JOIN performance_schema.events_statements_current waiting
    ON w.THREAD_ID = waiting.THREAD_ID
JOIN performance_schema.events_statements_current blocking
    ON w.BLOCKING_THREAD_ID = blocking.THREAD_ID;

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式