2. 数据库锁基础:锁的粒度、类型与兼容性矩阵
锁是数据库并发控制的核心机制,用于保证事务隔离性与数据一致性。理解锁的粒度、类型及其兼容关系,是排查锁等待与死锁问题的前提。本节从三个维度系统梳理数据库锁的基础知识。
2.1 锁的粒度
锁粒度指锁定资源的大小范围。粒度越细,并发度越高,但锁管理开销越大;粒度越粗,并发度越低,但开销小。主流数据库支持以下三种粒度:
| 粒度 | 锁定范围 | 并发度 | 开销 | 典型场景 |
|---|---|---|---|---|
| 行锁 | 单行记录 | 高 | 高 | OLTP 高并发更新、InnoDB 默认 |
| 页锁 | 数据页(通常 4KB~16KB) | 中 | 中 | SQL Server、MySQL BDB 引擎 |
| 表锁 | 整张表 | 低 | 低 | DDL 操作、MyISAM 引擎、批量维护 |
实战提示:MySQL InnoDB 默认使用行锁,但若查询未走索引,行锁会升级为表锁,导致并发骤降。排查锁等待时,优先检查 SQL 是否命中索引。
2.2 锁的类型
根据读写行为,锁分为共享锁与排他锁;为提升多粒度加锁效率,数据库引入意向锁。三种基本类型定义如下:
- 共享锁(S Lock,Shared Lock):允许持有事务读取数据,其他事务可继续加 S 锁,但不能加 X 锁。对应
SELECT ... LOCK IN SHARE MODE。 - 排他锁(X Lock,Exclusive Lock):允许持有事务读写数据,其他事务不能加任何锁。对应
SELECT ... FOR UPDATE或UPDATE/DELETE。 - 意向锁(Intention Lock):表级锁,用于快速判断表内是否已有行级锁,避免逐行检查。分为意向共享锁(IS)和意向排他锁(IX)。
关键理解:意向锁不阻塞任何行级锁请求,只用于表级锁与行级锁之间的协议通信。例如,事务在行上加 X 锁前,必须先在该表上加 IX 锁。
2.3 锁的兼容性矩阵
锁兼容性决定两个锁能否同时加在同一资源上。下表列出 S、X、IS、IX 四种锁在表级或行级上的兼容关系:
| 已持有锁 → 请求锁 ↓ |
共享锁(S) | 排他锁(X) | 意向共享锁(IS) | 意向排他锁(IX) |
|---|---|---|---|---|
| 共享锁(S) | ✅ 兼容 | ❌ 冲突 | ✅ 兼容 | ❌ 冲突 |
| 排他锁(X) | ❌ 冲突 | ❌ 冲突 | ❌ 冲突 | ❌ 冲突 |
| 意向共享锁(IS) | ✅ 兼容 | ❌ 冲突 | ✅ 兼容 | ✅ 兼容 |
| 意向排他锁(IX) | ❌ 冲突 | ❌ 冲突 | ✅ 兼容 | ✅ 兼容 |
排查要点:锁等待通常发生在 X 锁与 S/X 锁冲突时。若监控发现大量 IX 锁等待 IX 锁,往往不是锁冲突,而是资源排队(如 IO 慢、大事务未提交)。注意区分“锁冲突”与“锁等待”。
2.4 锁等待与死锁的初步判断
基于锁兼容性矩阵,可以快速定位锁等待原因:
- 锁等待:事务 B 请求的锁与事务 A 已持有的锁不兼容,B 进入等待队列。常见于
SELECT ... FOR UPDATE与UPDATE冲突。 - 死锁:事务 A 等待 B 释放锁,事务 B 同时等待 A 释放锁,形成循环等待。数据库会自动检测并回滚代价较小的事务。
排查口诀:“S 不挡 S,X 挡所有;IX 只挡 S/X,不挡 IS/IX。” 记住这个口诀,90% 的锁等待场景可以快速归因。