MySQL官方版本(含8.0+)不支持页级锁;InnoDB默认行锁,但索引失效时退化为表锁,锁实际加在索引记录上而非物理行。

InnoDB 默认用行级锁,但MySQL 官方版本(包括 8.0+)不支持页级锁。所谓“页级锁”在 MySQL 生态里基本是误传或混淆——它不属于 InnoDB、MyISAM 或任何官方引擎的可配置行为。
InnoDB 行锁实际生效的前提是走索引
-
行锁不是按“物理行”锁,而是锁住索引记录(
Record Lock),所以:-
WHERE id = 100(id是主键或唯一索引)→ 精确锁单行 -
WHERE name = 'Alice'(name无索引)→ 全表扫描 → 升级为表级锁(效果等同阻塞整张表) -
WHERE create_time > '2025-01-01'(有索引但范围大)→ 可能触发Gap Lock或Next-Key Lock,锁住索引区间而非单行
-
-
实操建议:
- 用
EXPLAIN检查 DML 是否命中索引 - 避免在 WHERE 中对字段做函数操作(如
YEAR(create_time) = 2025) - 少用
SELECT * FROM t WHERE 1类全表条件更新,极易退化为表锁
- 用
所谓“页级锁”在 MySQL 中并不存在可配置开关
innodb_locks_unsafe_for_binlog这类参数控制的是间隙锁是否启用,不是切换锁粒度page在 InnoDB 内部确实是数据组织单位(16KB 页),但用户无法直接申请“页锁”-
真正支持页级锁的引擎是 MariaDB 的
Aria,或老版 Berkeley DB;MySQL 用户碰到“页锁”说法,99% 是文档过时或张冠李戴
MySQL8 CRM Schema Design Expert下载面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
常见误判场景:
- 看到
SHOW ENGINE INNODB STATUS输出里有 “page no” 字样,误以为正在用页锁 - 把
ibdata1文件中页的物理结构,等同于锁机制中的“页级锁” - 将锁等待日志中出现多个行锁集中在同一数据页,理解成“系统自动合并为页锁”
- 看到
高并发写场景下,真正要盯的是锁升级和长事务
-
行锁本身不会“变成”页锁,但可能因以下原因扩大影响:
- 事务中执行了未提交的
SELECT ... FOR UPDATE后又做了全表更新 -
UPDATE影响行数过多(比如 50 万行),InnoDB 可能放弃逐行加锁而直接锁表(尤其在低内存或高负载时) - 长事务持有行锁不释放,导致其他事务在相同索引位置反复等待
- 事务中执行了未提交的
-
快速定位方法:
- 查
information_schema.INNODB_TRX看运行超 5 秒的事务 - 结合
performance_schema.data_locks观察当前持有的锁类型与对象 - 注意
LOCK WAIT状态线程是否卡在某个索引名上,而不是“页号”
- 查
真正的复杂点不在“选哪种锁”,而在索引设计是否匹配业务更新模式,以及事务边界是否足够短。锁粒度是引擎自动决定的,你只能通过 SQL 写法和索引结构去引导它。










