页级锁锁的是MySQL中BDB引擎的数据页(16KB物理存储单元),而非逻辑行或整表;它已随BDB在MySQL 5.1弃用、8.0彻底移除,InnoDB实际使用行锁+间隙锁,不存在页级锁。

页级锁到底锁的是什么?
页级锁不是锁“一页纸”,而是锁 MySQL 中的“数据页”——InnoDB 默认页大小为 16KB,一个页里通常包含多行记录(比如几十到上百行)。BDB 引擎(Berkeley DB)把这整页当作最小加锁单位:只要事务修改了页内任意一行,整个页就被加上排他锁;读操作则可能加共享页锁。它比表锁细、比行锁粗,本质是**用空间换时间的折中**:避免为每行单独申请锁资源,又不至于像表锁那样阻塞全表。
- 锁定范围是物理存储单元(page),不是逻辑行或整表
- 同一页内的不同行无法被不同事务并发修改(哪怕它们索引完全不同)
- BDB 已在 MySQL 5.1 后基本被弃用,现代生产环境几乎见不到页级锁的实际使用
-
SHOW ENGINE INNODB STATUS 不会报告页级锁,因为它不属于 InnoDB
BDB 的页级锁和 InnoDB 的行锁能混用吗?
不能。页级锁是 BDB 存储引擎的专属行为,而 InnoDB 虽然内部也按页组织数据,但它的行锁机制完全基于索引项(index record),与页物理结构无关。即使你手动指定 ENGINE=BDB,MySQL 8.0+ 已彻底移除 BDB 支持;5.6 及更早版本中启用 BDB 也需要编译时开启,且不支持事务隔离级别控制。
- MySQL 官方从 5.1 开始就将 BDB 标记为“deprecated”,5.6 起默认不编译,8.0 完全删除
-
CREATE TABLE ... ENGINE=BDB 在新版 MySQL 会直接报错:Unknown storage engine 'BDB'
- 别试图用
innodb_locks_unsafe_for_binlog 或其它参数“模拟”页级行为——那只会引发不可控的锁升级
为什么现在提页级锁容易踩坑?
因为大量中文资料把“InnoDB 的间隙锁(gap lock)+ 行锁组合效果”误称为“页级锁”,或者把“索引扫描导致的锁范围扩大”现象归因为页级粒度。实际上:
InnoDB 永远不会因“扫描了某页”就锁整页,它只锁满足条件的索引记录(含 gap)
如果 SQL 没走索引,InnoDB 退化为锁全表(table-level lock),不是锁页
EXPLAIN 显示 type: ALL 或 key: NULL 时,基本可以确定触发的是表锁,而非页锁
看执行计划比查文档更可靠:锁行为由优化器决定,不是由引擎“默认策略”决定
SELECT * FROM t WHERE id > 100 AND id < 200 FOR UPDATE —— 若 id 有索引,只锁匹配的索引项及间隙;若没索引,锁整张 t 表
所谓“页级并发度一般”,在今天已无实测价值:BDB 不可用,InnoDB 不提供页级锁接口
SHOW ENGINE INNODB STATUS 不会报告页级锁,因为它不属于 InnoDB ENGINE=BDB,MySQL 8.0+ 已彻底移除 BDB 支持;5.6 及更早版本中启用 BDB 也需要编译时开启,且不支持事务隔离级别控制。
- MySQL 官方从 5.1 开始就将 BDB 标记为“deprecated”,5.6 起默认不编译,8.0 完全删除
-
CREATE TABLE ... ENGINE=BDB在新版 MySQL 会直接报错:Unknown storage engine 'BDB' - 别试图用
innodb_locks_unsafe_for_binlog或其它参数“模拟”页级行为——那只会引发不可控的锁升级
为什么现在提页级锁容易踩坑?
因为大量中文资料把“InnoDB 的间隙锁(gap lock)+ 行锁组合效果”误称为“页级锁”,或者把“索引扫描导致的锁范围扩大”现象归因为页级粒度。实际上:
InnoDB 永远不会因“扫描了某页”就锁整页,它只锁满足条件的索引记录(含 gap)
如果 SQL 没走索引,InnoDB 退化为锁全表(table-level lock),不是锁页
EXPLAIN 显示 type: ALL 或 key: NULL 时,基本可以确定触发的是表锁,而非页锁
看执行计划比查文档更可靠:锁行为由优化器决定,不是由引擎“默认策略”决定
SELECT * FROM t WHERE id > 100 AND id < 200 FOR UPDATE —— 若 id 有索引,只锁匹配的索引项及间隙;若没索引,锁整张 t 表
所谓“页级并发度一般”,在今天已无实测价值:BDB 不可用,InnoDB 不提供页级锁接口
InnoDB 永远不会因“扫描了某页”就锁整页,它只锁满足条件的索引记录(含 gap)
如果 SQL 没走索引,InnoDB 退化为锁全表(table-level lock),不是锁页
EXPLAIN 显示 type: ALL 或 key: NULL 时,基本可以确定触发的是表锁,而非页锁
看执行计划比查文档更可靠:锁行为由优化器决定,不是由引擎“默认策略”决定
SELECT * FROM t WHERE id > 100 AND id < 200 FOR UPDATE —— 若 id 有索引,只锁匹配的索引项及间隙;若没索引,锁整张 t 表
所谓“页级并发度一般”,在今天已无实测价值:BDB 不可用,InnoDB 不提供页级锁接口
页级锁是个历史概念,它存在的意义只在于帮我们理解锁粒度设计的光谱——表锁太粗、行锁太细,中间曾有过一次尝试。现在真正要盯住的,是你的 SQL 走不走索引、优化器选不选对索引、事务里有没有隐式锁等待。其他都是背景噪音。










