Postgres:SELECT FOR UPDATE 在锁定释放后看不到新行
Postgres: SELECT FOR UPDATE does not see new rows after lock release
尝试在我的应用程序中支持 PostgreSQL DB,发现了这个奇怪的行为。
准备:
CREATE TABLE test(id INTEGER, flag BOOLEAN);
INSERT INTO test(id, flag) VALUES (1, true);
假设两个并发事务(Autocommit=false,READ_COMMITTED)TX1 和 TX2:
TX1:
UPDATE test SET flag = FALSE WHERE id = 1;
INSERT INTO test(id, flag) VALUES (2, TRUE);
-- (wait, no COMMIT yet)
TX2:
SELECT id FROM test WHERE flag=true FOR UPDATE;
-- waits for TX1 to release lock
现在,如果我 COMMIT in TX1,SELECT in TX2 returns 空游标。
这对我来说很奇怪,因为在 Oracle 和 MariaDB 中进行的相同实验会导致选择新创建的行 (id=2)。
我在 PG 文档中找不到有关此行为的任何信息。
我错过了什么吗?
有没有办法强制PG服务器在获取锁后"refresh"声明可见性?
PS: PostgreSQL 版本 11.1
TX2 扫描 table 并尝试锁定结果。
扫描从查询开始就看到了数据库的快照,因此它看不到通过 []之后 [=] 开始的并发修改插入(或以其他方式符合条件)的任何行=31=] 拍摄了快照。
这就是为什么您看不到带有 id
2.
的行的原因
对于 id
1,这也是正确的,因此扫描找到该行。但是查询必须等到锁被释放。当最终发生这种情况时,它会获取该行的最新提交版本并再次执行检查,以便该行也被排除在外。
此“EvalPlanQual”重新检查(使用 PostgreSQL 术语)仅针对在扫描期间找到但被锁定的行执行。扫描期间甚至没有找到第二行,因此那里没有发生此类处理。
这有点奇怪,承认。但这不是错误,这只是 PostgreSQL 的工作方式。
如果要避免此类异常,请使用 REPEATABLE READ
隔离级别。那么在这种情况下你会得到一个序列化错误并且可以重试交易,从而避免这样的不一致。
尝试在我的应用程序中支持 PostgreSQL DB,发现了这个奇怪的行为。
准备:
CREATE TABLE test(id INTEGER, flag BOOLEAN);
INSERT INTO test(id, flag) VALUES (1, true);
假设两个并发事务(Autocommit=false,READ_COMMITTED)TX1 和 TX2:
TX1:
UPDATE test SET flag = FALSE WHERE id = 1;
INSERT INTO test(id, flag) VALUES (2, TRUE);
-- (wait, no COMMIT yet)
TX2:
SELECT id FROM test WHERE flag=true FOR UPDATE;
-- waits for TX1 to release lock
现在,如果我 COMMIT in TX1,SELECT in TX2 returns 空游标。
这对我来说很奇怪,因为在 Oracle 和 MariaDB 中进行的相同实验会导致选择新创建的行 (id=2)。
我在 PG 文档中找不到有关此行为的任何信息。 我错过了什么吗? 有没有办法强制PG服务器在获取锁后"refresh"声明可见性?
PS: PostgreSQL 版本 11.1
TX2 扫描 table 并尝试锁定结果。
扫描从查询开始就看到了数据库的快照,因此它看不到通过 []之后 [=] 开始的并发修改插入(或以其他方式符合条件)的任何行=31=] 拍摄了快照。
这就是为什么您看不到带有 id
2.
对于 id
1,这也是正确的,因此扫描找到该行。但是查询必须等到锁被释放。当最终发生这种情况时,它会获取该行的最新提交版本并再次执行检查,以便该行也被排除在外。
此“EvalPlanQual”重新检查(使用 PostgreSQL 术语)仅针对在扫描期间找到但被锁定的行执行。扫描期间甚至没有找到第二行,因此那里没有发生此类处理。
这有点奇怪,承认。但这不是错误,这只是 PostgreSQL 的工作方式。
如果要避免此类异常,请使用 REPEATABLE READ
隔离级别。那么在这种情况下你会得到一个序列化错误并且可以重试交易,从而避免这样的不一致。