全书目录

第八篇:PostgreSQL 完全指南 —— 时间档案馆宇宙

第八章:锁 —— MVCC 不是没有锁,而是少用锁

2 分钟 464 字 第 172 / 962 个阅读单元

很多人听完 MVCC 会误以为:

“PostgreSQL 不靠锁。”

不对。

更准确地说是:

PostgreSQL 尽量不用锁解决读写可见性问题,但仍然大量使用锁解决冲突问题。

锁分几类,你先抓最实用的两类:

1. 表级锁 用于控制整个表上的某些操作能不能并行。

例如:

  • 普通 SELECT 拿很弱的锁
  • TRUNCATE 会拿很强的锁
  • 某些 DDL 会阻塞别的读写

2. 行级锁 用于控制“同一行”能不能被别人改。

例如抢占一张通行证:

sql
BEGIN;

SELECT *
FROM permits
WHERE permit_id = 42
FOR UPDATE;

-- 当前事务确认后再改
UPDATE permits
SET status = 'revoked'
WHERE permit_id = 42;

COMMIT;

FOR UPDATE 的意思可以理解为:

先把这份档案拿到锁柜里,别人现在不能改它。

常见行锁模式有:

  • FOR UPDATE
  • FOR NO KEY UPDATE
  • FOR SHARE
  • FOR KEY SHARE

你不用一开始全背,但要记住:

查询也可以加锁。

最常见的死锁长这样:

text
事务 A:先锁 1 号档案,再等 2 号档案
事务 B:先锁 2 号档案,再等 1 号档案

于是彼此卡死。

PostgreSQL 会自动检测死锁,并回滚其中一个事务。

避免死锁最有效的方法,不是祈祷,而是:

  • 多表、多行更新时保持固定顺序
  • 事务尽量短
  • 不要开着事务等用户点按钮
  • 真要高一致性,做好失败重试