postgresql如何在“已提交读取”隔离级别中出现“更新丢失”?

gk7wooem  于 2023-03-12  发布在  PostgreSQL
关注(0)|答案(1)|浏览(366)

PostgreSQL 14 Internals 的第52页上,Egor Rogov指出“已提交读取”隔离级别可能会发生“丢失更新”。
但在 * 某些情况下 *,存在丢失Read Committed级别更改的风险。
我想了解一下(特殊的?)情况是什么。在什么情况下会发生这种异常?

noj0wjuj

noj0wjuj1#

简短的回答是 * 没有这样的情况 *。
作者想到的“特殊情况”不是Postgres可能丢失更新,而是Postgres所在的大型系统似乎丢失了更新。这种情况要求并发事务中的用户重用先前读取的值,而忽略了在初始读取和重用之间,某人的提交可能会使值过时的事实。
问题是,如果您想这样做,您应该使用repeatable read模式和/或select for update(或另一个explicit lock),锁定您计划更新的行。
PDF version中,您提到的引文位于第44页。第52页描述了上述更新丢失的情况:
应用程序读取并注册(在数据库之外)Alice帐户的当前余额:

=> BEGIN;
 => SELECT amount FROM accounts WHERE id = 1;
 amount
 −−−−−−−−
 800.00
 (1 row)

同时,另一个事务执行相同的操作:

=> BEGIN;
 => SELECT amount FROM accounts WHERE id = 1;
 amount
 −−−−−−−−
 800.00
 (1 row)

第一个事务将以前注册的值增加$800,并提交此更改:

=> UPDATE accounts SET amount = 800.00 + 100 WHERE id = 1
RETURNING amount;
amount
−−−−−−−−
900.00
(1 row)
UPDATE 1
=> COMMIT;

第二个事务执行相同的操作:

=> UPDATE accounts SET amount = 800.00 + 100 WHERE id = 1
RETURNING amount;
amount
−−−−−−−−
900.00
(1 row)
UPDATE 1

很遗憾,Alice丢失了$100。数据库系统不知道$800的注册值与accounts.amount有某种关系,因此无法防止丢失更新异常。在“已提交读”隔离级别,此代码是不正确的。

相关问题