在 PostgreSQL 中执行第二个事务时,如何排除读取第一个事务中选择的行?

问题描述 投票:0回答:2

我有一个包含 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 个事务时。两个事务都返回第一行。

我做错了什么?我怎样才能达到我的期望?

postgresql transactions pessimistic-locking rowlocking
2个回答
0
投票

好吧,您的查询一开始就格式不正确,因为您没有提供

ORDER BY
,因此无法保证您在任一过程中都会得到哪个。

如果确实有订单,您应该看到的是第二个进程挂起,等待第一个进程提交或回滚。

你想要的是类似的东西

SELECT ... FOR UPDATE SKIP LOCKED

但是,您可能想要使用

FOR NO KEY UPDATE
(假设您没有更新密钥),因为这很可能是一个较轻的锁定(特别是如果您有外键指向该表 AIUI)。


0
投票

您的期望是错误的 - 正如其他答案中所解释的。

为什么在两个连接中使用 locked

for update
读取同一行的解释很可能是使用 DBeaver 的 Auto-Commit 模式(查询后立即释放锁定)。 您必须切换到

手动提交

模式才能看到第二个会话正在等待。

© www.soinside.com 2019 - 2024. All rights reserved.