我使用这样的查询:
INSERT INTO table
SELECT * FROM table2 t2
JOIN ...
...
WHERE table2.date < now() - '1 day'::INTERVAL
FOR UPDATE OF t2 SKIP LOCKED
ON CONFLICT (...)
DO UPDATE SET ...
RETURNING *;
我的问题是FOR UPDATE t2 SKIP LOCKED
。我应该在这里使用吗?或者Postgres会自动使用INSERT SELECT ON CONFLICT
锁定这些行,直到交易结束?
我的目标是阻止其他应用(同时)捕获内部SELECT
已被此捕获的行。
答案 0 :(得分:1)
是的,FOR UPDATE OF t2 SKIP LOCKED
是使用默认Read Committed transaction isolation来阻止竞争条件的正确方法。
添加的SKIP LOCKED
也可以防止死锁。请注意,竞争交易可能会从SELECT
获得部分集合 - 无论它可以先锁定。
虽然Postgres中的任何事务都是原子的,但它不会阻止另一个(也是原子的)事务选择(并插入 - 或至少尝试)同一行,因为SELECT
没有 FOR UPDATE
不会exclusive lock。
Postgres manual about transactions:
事务被称为 atomic :从其他事务的角度来看,它要么完全发生,要么根本不发生。
相关:
澄清:
像INSERT
这样的SQL DML命令始终是 atomic ,因为它不能在事务外运行。但您不能说INSERT
是一笔交易。错误的术语。
在Postgres 中,所有锁都会保留,直到当前交易结束时才会发布。