Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

MySQL 锁

覆盖:核心概念、锁类型、加锁方式、锁等待、死锁、诊断、优化、实战案例。

🧱 1. 锁的核心概念(必须先理解)

MySQL 主流存储引擎是 InnoDB,锁机制围绕事务、行级锁、MVCC 等展开。理解锁的目的:

为什么需要锁?

  • 保证事务隔离
  • 防止并发冲突
  • 保证数据一致性
  • 提高并发性能(行锁比表锁更 granular)

MySQL 中“锁 + MVCC + 事务隔离级别”三者配合

  • 锁:阻塞写,部分情况下阻塞读
  • MVCC:让读尽量不加锁
  • 事务隔离级别:控制读写冲突何时需要锁

掌握这三者的关系,是理解 MySQL 并发行为的基础。

🧱 2. MySQL(InnoDB)锁类型全图

下面是 MySQL 里所有重要锁(完整体系化):

2.1 从“锁的粒度”区分

类型 说明
全局锁(Global Lock) FLUSH TABLES WITH READ LOCK(FTWRL);逻辑备份常用;影响全库
表级锁(Table Lock) MySQL 层面的表锁;DDL 使用
元数据锁(MDL) 保证 DDL 与 DML 不冲突
行级锁(Row Lock) InnoDB 的核心锁;精细锁粒度
间隙锁(Gap Lock) 阻止幻读;锁不存在的记录范围
临键锁(Next-Key Lock) 行锁 + 间隙锁;RR 隔离级别默认
插入意向锁(Insert Intention Lock) 插入前的范围锁,用于协调 Insert 并发

2.2 从“锁的属性”区分

属性 类型 说明
读锁 S 锁(Shared Lock) 可共享读
写锁 X 锁(Exclusive Lock) 独占写
意向锁 IS, IX 用于加速判断是否能在行级加锁
AUTO-INC 锁 自增字段上的轻量锁 INSERT 时序保证
隐式锁 insert 时自动产生,不需要显式锁结构 MVCC + undo 支持

🧱 3. InnoDB 行锁(InnoDB 的核心锁)

行锁分类

锁类型 说明
Record Lock(记录锁) 锁单行记录
Gap Lock(间隙锁) 锁一个范围但不含目标记录
Next-Key Lock(临键锁) 记录锁 + Gap;用于防止幻读
Insert Intention Lock INSERT 时对 gap 加的锁

加锁行为由三个因素决定

  1. 事务隔离级别(如 RR 会自动加 gap/next-key)
  2. 是否走索引
  3. 是否是精准匹配(索引等值查询)

🔥 重点:没有走索引 = 锁全表 = 性能灾难

必须牢记这一点。

🧱 4. 锁是如何加上的?(必须理解的规则)

以下规则帮助你准确判断 SQL 会锁什么。

4.1 精准等值查询 + 唯一索引 -> 行锁

SELECT * FROM users WHERE id = 10 FOR UPDATE;

-> 加 record lock(单行)

4.2 等值查询但非唯一索引 -> next-key lock / gap lock

SELECT * FROM users WHERE age = 20 FOR UPDATE;

可能锁住多个范围,而不是单条。

4.3 范围查询 -> next-key

SELECT * FROM users WHERE age > 20 FOR UPDATE;

-> 锁整个范围 -> 容易出现锁等待

4.4 未使用索引 -> 全表锁(行锁退化为表锁)

SELECT * FROM users WHERE name LIKE '%abc%' FOR UPDATE;

-> 锁全表(灾难级)

4.5 INSERT 会加 Insert Intention Lock

多个插入能并发执行,不会相互阻塞。

🧱 5. MySQL 锁等待与死锁

5.1 查看锁等待

SELECT * FROM information_schema.innodb_locks;
SELECT * FROM information_schema.innodb_lock_waits;
SELECT * FROM information_schema.innodb_trx;

5.2 查看等待链

SELECT * FROM performance_schema.data_lock_waits;

🧱 6. 死锁排查(最重要)

6.1 查看死锁日志

SHOW ENGINE INNODB STATUS;

重点看:

  • LATEST DETECTED DEADLOCK
  • 哪个事务被杀
  • 锁类型(record, next-key, gap)
  • 触发语句

🧱 7. 锁优化策略(最终总结)

7.1 SQL 层面优化

  • 必须使用 索引(避免锁全表)
  • 等值查询尽量使用 唯一索引
  • 避免范围查询 + FOR UPDATE
  • 避免大事务(大事务锁范围大)
  • DML 语句必须带条件(WHERE / LIMIT)

7.2 事务层面优化

  • 尽快提交事务(短事务)
  • 减少业务逻辑放在事务内部
  • 尽量按固定顺序访问表(避免死锁)
  • 禁止事务里执行外部 RPC 或耗时操作

7.3 高并发场景的设计优化

  • 减少锁冲突 -> 最小化热点
  • 用 Redis 或分布式锁降低数据库争抢
  • MySQL 里热点计数可以使用:
  • 分库拆表
  • 乐观锁(version 字段)
  • 行级锁控制更新顺序(FOR UPDATE)

7.4 配置层面优化(回复2 内容融合)

参数 说明
innodb_lock_wait_timeout 锁等待时长
innodb_deadlock_detect 死锁检测开关
innodb_print_all_deadlocks 打印所有死锁
transaction_isolation 建议使用 RC 提升并发

🧱 8. 最重要的实战案例(全覆盖)

案例 1:范围查询导致大面积加锁

UPDATE orders SET status=1 WHERE id > 1000;
  • 锁住巨大范围
  • 大量锁等待

解决:分批更新

UPDATE orders SET status=1 WHERE id > 1000 LIMIT 500;

案例 2:未走索引导致全表锁

SELECT * FROM user WHERE email LIKE '%@gmail.com%' FOR UPDATE;
  • 索引失效
  • 锁全表

解决:改成反向存储等方式

案例 3:死锁典型(两个事务访问顺序不一致)

  • 事务 A:先锁用户表 -> 再锁订单表
  • 事务 B:先锁订单表 -> 再锁用户表

-> 环路 -> 死锁

解决:访问顺序统一

user -> order 统一顺序即可避免大多数死锁

🧱 9. 最终总结(极速复盘)

  • MySQL 锁 = 行锁 + 间隙锁 + 临键锁 + 意向锁 + MDL + AUTO-INC
  • 使用索引 = 避免行锁退化为表锁
  • RR 隔离级别 = 默认产生 Next-Key 锁
  • 死锁本质 = 两个事务循环等待
  • 最好的手段 = SQL 优化 + 索引设计 + 事务最小化