MySQL 中的锁机制是保证数据一致性和并发控制的核心,主要分为以下几种类型(按粒度从大到小排列):
一、按锁的粒度分类
1. 全局锁(Global Lock)
- 作用:锁定整个数据库实例(
FLUSH TABLES WITH READ LOCK
)。 - 场景:
全库逻辑备份时,确保数据一致性(类似“只读模式”)。 - 问题:
阻塞所有写操作,业务基本停摆(慎用)。
2. 表级锁(Table-Level Lock)
- ① 表锁(显式锁)
- 语法:
LOCK TABLES table_name READ/WRITE
。 - 特点:手动加锁,需显式释放(
UNLOCK TABLES
)。
- 语法:
- ② 元数据锁(Metadata Lock, MDL)
- 自动加锁:执行 DML(增删改查)时加 MDL 读锁;执行 DDL(表结构变更)时加 MDL 写锁。
- 阻塞问题:
DDL 会等待所有 DML 释放读锁 → 长事务可能阻塞 DDL 操作(常见线上事故原因!)。
- ③ 意向锁(Intention Lock)
- 作用:快速判断表中是否有行级锁(避免遍历每行)。
- 类型:
- 意向共享锁(IS):事务准备给某些行加 S 锁。
- 意向排他锁(IX):事务准备给某些行加 X 锁。
3. 行级锁(Row-Level Lock)
由 InnoDB 引擎实现,基于索引生效(无索引则退化为表锁!)
- ① 记录锁(Record Lock)
- 锁定索引中的单行记录(即使表无索引,也会在隐藏聚簇索引上加锁)。
- ② 间隙锁(Gap Lock)
- 锁定索引记录之间的间隙(开区间,如
(5, 10)
)。 - 作用:防止其他事务在间隙中插入数据(解决幻读)。
- 锁定索引记录之间的间隙(开区间,如
- ③ 临键锁(Next-Key Lock)
- 记录锁 + 间隙锁(左开右闭区间,如
(5, 10]
)。 - InnoDB 默认行锁算法(可重复读隔离级别下使用)。
- 记录锁 + 间隙锁(左开右闭区间,如
- ④ 插入意向锁(Insert Intention Lock)
- 特殊间隙锁:在 INSERT 操作前设置,表示想在某个间隙插入数据(不同事务插入不同位置不冲突)。
4. 自增锁(AUTO-INC Lock)
- 作用:保障自增主键(
AUTO_INCREMENT
)的连续分配。 - 模式:
innodb_autoinc_lock_mode=0
(传统模式):语句执行完才释放。innodb_autoinc_lock_mode=1
(默认):批量插入时轻量级锁。innodb_autoinc_lock_mode=2
:全并发(可能不连续,但性能最佳)。
二、按锁的兼容性分类
锁类型 | X(排他锁) | S(共享锁) | IX(意向排他) | IS(意向共享) |
---|---|---|---|---|
X(排他锁) | ❌ 冲突 | ❌ 冲突 | ❌ 冲突 | ❌ 冲突 |
S(共享锁) | ❌ 冲突 | ✅ 兼容 | ❌ 冲突 | ✅ 兼容 |
IX(意向排他) | ❌ 冲突 | ❌ 冲突 | ✅ 兼容 | ✅ 兼容 |
IS(意向共享) | ❌ 冲突 | ✅ 兼容 | ✅ 兼容 | ✅ 兼容 |
- 共享锁(S):
SELECT ... LOCK IN SHARE MODE
- 排他锁(X):
SELECT ... FOR UPDATE
/ DML 语句自动加锁
三、其他重要锁机制
1. 死锁检测与处理
- 检测:InnoDB 使用等待图(wait-for graph) 检测死锁(默认开启)。
- 处理:强制回滚代价较小的事务(
innodb_deadlock_detect=ON
)。
2. 锁监控
-- 查看当前锁信息
SHOW ENGINE INNODB STATUS; -- 关注 `TRANSACTIONS` 和 `LATEST DETECTED DEADLOCK` 部分
-- 查看锁等待
SELECT * FROM information_schema.INNODB_LOCKS;
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
四、锁机制总结表
锁类型 | 粒度 | 作用场景 | 关键特性 |
---|---|---|---|
全局锁 | 数据库级别 | 全库备份 | 阻塞所有写操作 |
表锁 | 表级别 | 显式锁定整表 | 手动控制,谨慎使用 |
元数据锁(MDL) | 表级别 | DML/DDL 并发控制 | 长事务阻塞 DDL 常见问题源 |
意向锁(IS/IX) | 表级别 | 快速检测行锁存在 | 提高行锁检测效率 |
记录锁(Record) | 行级别 | 锁定单行记录 | 基于索引生效 |
间隙锁(Gap) | 行级别 | 防止幻读 | 锁定区间,RR 隔离级别使用 |
临键锁(Next-Key) | 行级别 | 默认行锁(记录锁+间隙锁) | RR 隔离级别防幻读核心机制 |
插入意向锁 | 行级别 | INSERT 前预声明插入位置 | 减少插入操作的锁冲突 |
自增锁 | 表级别 | 保障自增主键连续分配 | 模式影响并发性能 |
五、最佳实践建议
- 优先使用行级锁:减少锁冲突,提高并发(确保 SQL 用上索引)。
- 避免长事务:及时提交事务,减少 MDL 锁和间隙锁持有时间。
- 监控锁等待:定期检查
INNODB_LOCKS
和INNODB_LOCK_WAITS
。 - 谨慎使用 DDL:在低峰期操作,避免被长事务阻塞。
- 死锁处理:重试机制 > 死锁检测 > 调整事务粒度。
⚠️ 重点提醒:
- 间隙锁/临键锁只在
REPEATABLE READ
隔离级别生效(READ COMMITTED
下无效)。- 无索引的更新会导致全表行锁(实际退化为表锁),务必优化索引设计!