是INSERT ... SELECT一个原子事务?

时间:2017-10-19 14:06:00

标签: sql postgresql concurrency locking upsert

我使用这样的查询:

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已被此捕获的行。

1 个答案:

答案 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 中,所有锁都会保留,直到当前交易结束时才会发布。