我有一个包含 3 列的“用户”表。该表有2条记录有值
用户名 | 用户年龄 | 用户地址 |
---|---|---|
开尔文 | 18 | 纽约 |
托马斯 | 21 | 巴黎 |
第一笔交易
BEGIN ;
SELECT u from "user" u where u.user_age > 10 limit 1 for update ;
SELECT pg_sleep(15);
END;
第二笔交易在#1交易之后大约1秒开始。
BEGIN ;
SELECT u from "user" u where u.user_age > 10 limit 1 for update ;
END;
我预计第一笔交易将返回第一行(Kevin,18,纽约)。第二笔交易将返回第二行(Thomas,21,巴黎)。
但是当我在 DBeaver 的两个单独的选项卡中执行上面的 2 个事务时。两个事务都返回第一行。
我做错了什么?我怎样才能达到我的期望?
好吧,您的查询一开始就格式不正确,因为您没有提供
ORDER BY
,因此无法保证您在任一过程中都会得到哪个。
如果确实有订单,您应该看到的是第二个进程挂起,等待第一个进程提交或回滚。
你想要的是类似的东西
SELECT ... FOR UPDATE SKIP LOCKED
但是,您可能想要使用
FOR NO KEY UPDATE
(假设您没有更新密钥),因为这很可能是一个较轻的锁定(特别是如果您有外键指向该表 AIUI)。
您的期望是错误的 - 正如其他答案中所解释的。
为什么在两个连接中使用 locked 和
for update
读取同一行的解释很可能是使用 DBeaver 的 Auto-Commit 模式(查询后立即释放锁定)。
您必须切换到手动提交模式才能看到第二个会话正在等待。