乐观锁与悲观锁
比较 SELECT ... FOR UPDATE(悲观锁)与版本列 / WHERE updated_at = ?(乐观锁)模式
乐观锁与悲观锁 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。
两种并发策略
- 悲观策略 — 读取行时将其锁定,其他事务无法修改
- 乐观策略 — 不加锁;UPDATE 时验证该行是否仍未发生变化
悲观策略:SELECT ... FOR UPDATE
现在锁定,稍后写入:
BEGIN;
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;
-- other transactions cannot lock or update this row
-- compute new balance...
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;FOR SHARE
读锁——其他事务可以读取,但不能写入:
SELECT * FROM orders WHERE id = 1 FOR SHARE;
-- others can SELECT FOR SHARE but cannot UPDATE悲观策略的优缺点
优点:易于理解和推理,不需要重试。
缺点:降低并发性,可能导致锁等待和死锁。
乐观策略:版本列
读取时带上版本号,写入时使用 WHERE version = expected:
BEGIN;
SELECT id, balance, version FROM accounts WHERE id = 1;
-- compute new balance...
UPDATE accounts
SET balance = ?, version = version + 1
WHERE id = 1 AND version = ?;
-- check rows affected: 0 means someone else updated, retry使用更新时间的乐观策略
思路相同,但使用更新时间字段代替显式的版本列:
UPDATE accounts
SET balance = ?, updated_at = NOW()
WHERE id = ? AND updated_at = ?;
-- If updated_at has changed in the meantime, 0 rows affected — retry.乐观策略的优缺点
优点:并发性高,无需等待。
缺点:写入可能失败并需要重试逻辑;冲突只有在 UPDATE 时才会显现。
何时选择悲观策略
适用于:
- 热点行竞争激烈的短事务
- 资金转账——不希望只完成部分操作
- 可能发生冲突的长时间运行操作
何时选择乐观策略
适用于:
- 以读取为主且冲突很少的工作负载
- 客户端在请求之间持有该行的无状态接口
- 移动端或离线编辑后再同步
混合策略:FOR UPDATE NOWAIT
尝试加锁;如果已被锁定,则立即失败并让用户重试:
SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT;
-- ERROR if someone else holds it — user sees a friendly retry message咨询锁
不与任何行关联的应用级锁:
SELECT pg_try_advisory_xact_lock(hashtext('order:42'));
-- True if you got the lock, false otherwise — useful for cross-row coordination.不要忘记为锁定目标建立索引
如果 WHERE 列没有索引,FOR UPDATE 可能会锁定比预期更多的行(它会锁定扫描到的行,而不仅是匹配的行)。
锁超时
设置 lock_timeout,避免无限等待:
SET lock_timeout = '5s';
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- ERROR if lock not acquired in 5 seconds回顾
悲观策略锁定行;乐观策略在写入时检查。
- 悲观策略:FOR UPDATE——简单,但会降低并发性
- 乐观策略:版本列——并发性更高,但需要重试
- 根据工作负载选择,必要时组合使用
快速检查
电商库存扣减存在激烈竞争。通常哪种锁定策略更安全?
常见问题解答
「乐观锁与悲观锁」课时是免费的吗?
是的 — 「乐观锁与悲观锁」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。
「乐观锁与悲观锁」这节课中我会学到什么?
比较 SELECT ... FOR UPDATE(悲观锁)与版本列 / WHERE updated_at = ?(乐观锁)模式 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「乐观锁与悲观锁」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Academy 课中编写并运行代码吗?
能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。