在 PostgreSQL 14 Internals 的第52页上,Egor Rogov指出“已提交读取”隔离级别可能会发生“丢失更新”。但在 * 某些情况下 *,存在丢失Read Committed级别更改的风险。我想了解一下(特殊的?)情况是什么。在什么情况下会发生这种异常?
Read Committed
noj0wjuj1#
简短的回答是 * 没有这样的情况 *。作者想到的“特殊情况”不是Postgres可能丢失更新,而是Postgres所在的大型系统似乎丢失了更新。这种情况要求并发事务中的用户重用先前读取的值,而忽略了在初始读取和重用之间,某人的提交可能会使值过时的事实。问题是,如果您想这样做,您应该使用repeatable read模式和/或select for update(或另一个explicit lock),锁定您计划更新的行。在PDF version中,您提到的引文位于第44页。第52页描述了上述更新丢失的情况:应用程序读取并注册(在数据库之外)Alice帐户的当前余额:
repeatable read
select for update
=> 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有某种关系,因此无法防止丢失更新异常。在“已提交读”隔离级别,此代码是不正确的。
1条答案
按热度按时间noj0wjuj1#
简短的回答是 * 没有这样的情况 *。
作者想到的“特殊情况”不是Postgres可能丢失更新,而是Postgres所在的大型系统似乎丢失了更新。这种情况要求并发事务中的用户重用先前读取的值,而忽略了在初始读取和重用之间,某人的提交可能会使值过时的事实。
问题是,如果您想这样做,您应该使用
repeatable read
模式和/或select for update
(或另一个explicit lock),锁定您计划更新的行。在PDF version中,您提到的引文位于第44页。第52页描述了上述更新丢失的情况:
应用程序读取并注册(在数据库之外)Alice帐户的当前余额:
同时,另一个事务执行相同的操作:
第一个事务将以前注册的值增加$800,并提交此更改:
第二个事务执行相同的操作:
很遗憾,Alice丢失了$100。数据库系统不知道$800的注册值与accounts.amount有某种关系,因此无法防止丢失更新异常。在“已提交读”隔离级别,此代码是不正确的。