PostgreSQL中SELECT FOR UPDATE关联表时更新外键不返回行的问题
PostgreSQL SELECT FOR UPDATE 关联表+更新外键时返回空行的问题
根据PostgreSQL显式锁文档中的描述:
SELECT FOR UPDATE会等待对同一行执行过相关命令的并发事务,之后会锁定并返回更新后的行(若行已删除则返回空)。
但实际场景中遇到了不符合预期的情况:当更新某行的外键字段,且SELECT语句关联另一张表时,SELECT FOR UPDATE并未返回更新后的行;更新其他字段时则符合文档描述。此时被并发事务更新外键的行似乎不可见,表现得如同被删除。
极简复现示例
预期两个并发事务都能更新该行,但实际只有一个能成功,第二个事务返回空。若将第一个事务的更新语句改为更新非外键字段,则两个事务都能正常查询到该行,符合文档描述。
注意:SELECT语句关联了foo表(该表未被更新),实际场景中需获取foo表字段;若不关联表,即使更新外键也能正常工作。触发该现象的两个关键条件为:
- 更新外键字段
- SELECT语句使用JOIN关联表
create table foo(pk int primary key); create table bar(pk int, fk int references foo(pk), value int); insert into foo values (1), (2), (3); insert into bar values (1, 1, 1); ---- 第一个事务 begin; select * from bar join foo on foo.pk = bar.fk where bar.pk = 1 for update of bar; -- 此时并发执行第二个事务的SELECT语句,之后回到此处继续执行 update bar set fk = 2; -- 若改为更新value字段,第二个事务将正常返回行 -- update bar set value = 10; commit; ---- 第二个(并发)事务 begin; select * from bar join foo on foo.pk = bar.fk where bar.pk = 1 for update of bar; -- 继续执行第一个事务 -- 第一个事务提交后,此语句返回空;行未被锁定,无法更新 commit;
疑问
我在文档中遗漏了什么?该现象的原因是什么?希望能提供相关文档参考。
环境说明:该问题可在干净数据库中复现,无配置修改,使用Read Committed隔离级别。
内容的提问来源于stack exchange,提问作者Enkelli
相关产品推荐
相关产品推荐

