2

再会。我READ COMMITTED在 postgres 中使用隔离级别,发现不符合官方文档的奇怪行为。假设我有一张桌子account(id int,name text,amount int)和两行。

test> select * from account;                       
-[ RECORD 1 ]-------------------------
id     | 1
name   | Bob
amount | 800
-[ RECORD 2 ]-------------------------
id     | 2
name   | Bob
amount | 200

现在我开始两个 READ COMMITTED 事务。第一个执行以下查询

UPDATE account set amount = 100 where id = 2; -- 1

然后第二个执行这个查询

 UPDATE account set amount = amount+50 --2
  where name in 
      (select DISTINCT name from account group by
      name having sum(amount)>=1000); 

现在它被锁定了,因为第一个事务还没有提交。所以第二笔交易要给总金额大于或等于 1000 的每个账户加 50。由于 Bob 有两个账户(800+200),那么它应该给每个账户加 50。但是,现在第一个事务已提交COMMIT; --1,现在 Bob 总共有 900 个,根据文档读取提交的事务将

重新评估命令的搜索条件(WHERE 子句)以查看行的更新版本是否仍然匹配搜索条件。如果是这样,第二个更新程序使用该行的更新版本继续其操作

据我了解,第二笔交易将重新评估where 条件并跳过 Bob 的帐户。然而,当第二个事务被提交时,最后的行看起来像这样

id     | 1                                                                                            │
name   | Bob                                                                                          │
amount | 850                                                                                          │
-[ RECORD 3 ]-------------------------                                                                │
id     | 2                                                                                            │
name   | Bob                                                                                          │
amount | 150 

这意味着第二个事务没有重新评估搜索条件并对行应用更新,即使它们与条件不匹配。为什么会这样。我错过了文档中的某些内容吗?

4

1 回答 1

1

UPDATE一个事务中的 阻塞UPDATE第二个查询中的 ,但阻塞该查询中的子选择。子选择已经完成,总和已经确定为1000,所以UPDATE执行了,阻塞了。当锁消失时,不会重新评估子查询。

您从文档中引用的段落是关于SELECT ... FOR UPDATE(或FOR SHARE)的,您不使用它。它不能在您的示例中使用,因为它在使用聚合函数或分组的查询中没有意义。

于 2020-05-13T19:39:30.033 回答