在 PostgreSQL/openGauss 的底层工程史上,这 8 个锁级别是内核团队被 极高并发读写”和“在线不停机运维 这两个死要求,一步一步逼着演进而来的。
从 0 开始,面对不断增加的复杂业务场景,用极其严密的逻辑,一层一层把这 8 个“表级锁(Table-Level Locks)”被逼出来的全过程推导重演一遍!
演进第一阶段:最原始的“毁灭与查询”边界
数据库刚写出来,只有两种最基础的操作:查数据和删表。
场景 1: 用户海量并发执行 SELECT * FROM table;。
场景 2: DBA 执行 DROP TABLE、TRUNCATE 或 VACUUM FULL。
- 架构决断: 这两者绝对不能共存。如果你在删底层物理文件,别人绝不能读。
- 诞生了最极端的两极锁:
- 第 1 级:
AccessShareLock(纯读锁)。极度宽容,1 级和 1 级完美并发,只排斥彻底的毁灭。 - 第 8 级:
AccessExclusiveLock(绝对排他锁)。极度自私,只要加上,排斥其余所有 1 到 7 级锁。连查都不准查。
- 第 1 级:
演进第二阶段:引入 DML(增删改)与 MVCC
现在业务要上线了,大家需要写数据。
场景 3: 几千个并发执行 UPDATE table SET val=1 WHERE id=?。
- 架构痛点: 传统的数据库(比如早期的系统)一更新数据就锁表,导致别人没法
SELECT。但 PG 拥有强大的 MVCC(多版本并发控制),读写可以通过版本号互相避让!同时,这几千个UPDATE互相之间需要锁表排队吗?不需要!因为它们修改的是不同的行,底层的**物理行锁(xmax)**会解决微观冲突。 - 架构决断: 我们需要一个专门给 DML 用的表级锁,它的核心原则是:“绝不阻塞读,也绝不阻塞其他写,只防 DBA 删表。”
- 诞生了:
- 第 3 级:
RowExclusiveLock(行排他-表级锁)。- 逻辑拆解: “RowExclusive”的意思是“我声明我要去排他性地修改行了”。作为表锁,它允许 1 级(读)和 3 级(写)并发,它只负责在表头上挂个牌子:“里面有人在写数据,外面谁也不准执行 8 级
DROP TABLE”。
- 逻辑拆解: “RowExclusive”的意思是“我声明我要去排他性地修改行了”。作为表锁,它允许 1 级(读)和 3 级(写)并发,它只负责在表头上挂个牌子:“里面有人在写数据,外面谁也不准执行 8 级
- 第 3 级:
演进第三阶段:悲观并发的“占坑”诉求
财务系统上线了,需要极其严格的对账。
场景 4: 财务执行 SELECT * FROM account WHERE id=100 FOR UPDATE;。
- 架构痛点: 这句话本质上是
SELECT,没有修改任何数据,所以不能给它第 3 级锁。但它明确宣告了“我接下来肯定要修改”。如果只给它第 1 级锁,万一这时候有个运维脚本把表结构冻结了怎么办? - 架构决断: 我们需要一个介于“纯读”和“真写”之间的过渡锁。
- 诞生了:
- 第 2 级:
RowShareLock(行共享-表级锁)。- 逻辑拆解: 它比 1 级强一点。它同样允许别人 1 级读、3 级写。但它存在的核心目的,是为了排斥第 7 级锁(全表只读排他锁,后面会讲),确保自己在稍后真正执行
UPDATE时,表没有被冻结。
- 逻辑拆解: 它比 1 级强一点。它同样允许别人 1 级读、3 级写。但它存在的核心目的,是为了排斥第 7 级锁(全表只读排他锁,后面会讲),确保自己在稍后真正执行
- 第 2 级:
演进第四阶段:DBA 的灾难 —— 传统维护操作
表里的数据到了十个亿,查询太慢,DBA 必须建索引。
场景 5: DBA 执行标准的 CREATE INDEX。
- 架构痛点: 建普通的 B-Tree 索引,需要对全表数据进行排序和树结构组装。在这个长达几十分钟的过程中,绝对不能允许任何人执行
UPDATE或DELETE(第 3 级锁),否则树的指针就全乱了!但是,为了不让业务彻底瘫痪,必须允许大家继续执行SELECT(第 1 级锁)。 - 架构决断: 发明一个专门用于冻结写入,但不冻结读取的锁。
- 诞生了:
- 第 5 级:
ShareLock(共享锁)。- 逻辑拆解: 只要 DBA 敲下
CREATE INDEX,系统挂上 5 级锁。所有 1 级(纯读)瞬间放行,但所有 3 级(写)和 2 级(FOR UPDATE)全部被死死堵在门外排队。这就是为什么白天建普通索引会引发全站雪崩的底层逻辑!
- 逻辑拆解: 只要 DBA 敲下
- 第 5 级:
演进第五阶段:内核的伟大妥协 —— 在线热维护
随着互联网发展,业务要求 7×24 小时绝对在线。第 5 级锁“一建索引就堵死全站写入”的特性,完全无法忍受。
场景 6: DBA 需要做日常的 VACUUM(空间清理)和 CREATE INDEX CONCURRENTLY(并发建索引)。
- 架构痛点: 必须发明一种极其高级的算法,让建索引和清理垃圾的动作在后台“隐身”运行。它既不能挡住 1 级(读),也绝不能挡住 3 级(写)。但是!不能有两个 DBA 同时对一张表做
VACUUM,这会导致底层物理数据块的整理逻辑彻底错乱。 - 架构决断: 发明一种只排斥“同行”,不排斥“业务”的极客锁。
- 诞生了:
- 第 4 级:
ShareUpdateExclusiveLock(共享更新排他锁)。- 逻辑拆解: 它是 PG 运维体系里最伟大的锁!加上它之后,业务的读(1级)和写(3级)如入无人之境,丝毫不受影响。它只和自己(4级)以及破坏表结构的操作冲突。实现了完美的在线免停机维护。
- 第 4 级:
演进第六阶段:极其罕见的边缘防御(补齐矩阵缺口)
到这里,业务和 DBA 的主要诉求都满足了。最后,为了填补矩阵在极端场景下的逻辑缺口,内核补齐了 6 和 7。
场景 7: 极其复杂的结构微调(如 CREATE TRIGGER)。
- 诞生了:第 6 级
ShareRowExclusiveLock。- 逻辑拆解: 建触发器时,不仅不能让别人写数据(排斥 3 级),而且连 DBA 想在后台建个索引(排斥 4 级、5 级)都不行。这是一种偏防守的结构锁。
场景 8: 极其暴力的业务霸权(显式锁定全表只读)。
- 诞生了:第 7 级
ExclusiveLock。- 逻辑拆解: 某业务强行敲下
LOCK TABLE t IN EXCLUSIVE MODE。它宣告:“这张表现在被我接管了,除了允许别人做最基础的 1 级SELECT之外,任何人不准写数据(挡 3 级),甚至连SELECT FOR UPDATE(挡 2 级)都不准!”
- 逻辑拆解: 某业务强行敲下
架构师的终极复盘(逻辑闭环)
现在,你把这 8 个级别重新排队,用**“它到底挡住了什么”**的视角来看,逻辑就绝对平顺了:
- Level 1 (
SELECT): 什么业务都不挡。只挡 8 级删表。 - Level 2 (
FOR UPDATE): 不挡读写。只挡 7 级全表冻结和 8 级删表。 - Level 3 (
UPDATE/DELETE): 最常用的写锁。利用 MVCC 不挡读,利用行锁不挡其他写。开始挡 DBA 的传统维护(5级)。 - Level 4 (
VACUUM / CONCURRENT INDEX): 伟大的热维护锁。不挡读写。只挡同行(另一个 4 级)和 DDL。 - Level 5 (
CREATE INDEX): 霸道的冷维护锁。只允许读。彻底挡死所有写入(3级、2级)。 - Level 6 (
CREATE TRIGGER): 偏执的维护锁。不仅挡死写入,连热维护(4级)一起挡死。 - Level 7 (
LOCK TABLE): 业务层的霸王条款。冻结全表,只准纯读,其余全部挡死。 - Level 8 (
DROP TABLE): 核武器。毁灭一切,挡死一切。
这段推导,完全从业务发展 , 遇到并发瓶颈 , 创造新锁级别来解耦的工程视角出发。它解释了为什么 4 级(热维护)在对业务的影响上,反而比 3 级(写)和 5 级(冷维护)更小,打破了死记硬背的数字大小错觉。
了解 www.876873.xyz 的更多信息
订阅后即可通过电子邮件收到最新文章。
重量级锁/常规锁 的八大锁模式(冲突矩阵): 逻辑推导这8个 锁级别:等您坐沙发呢!