INSERT ... SELECT 是原子事务吗?

Son*_*que 5 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 *;
Run Code Online (Sandbox Code Playgroud)

我的问题是关于FOR UPDATE t2 SKIP LOCKED. 我应该在这里使用它吗?或者 Postgres 会自动锁定这些行直到INSERT SELECT ON CONFLICT事务结束吗?

我的目标是防止其他应用程序(同时)捕获SELECT已被该应用程序捕获的内部行。

Erw*_*ter 2

是的,这是通过默认的已提交读事务隔离FOR UPDATE OF t2 SKIP LOCKED来防止竞争条件的正确方法。

\n\n

添加的内容SKIP LOCKED还可以防止死锁。请注意,竞争事务可能每个都会从 - 无论它首先锁定的内容中获取部分集SELECT

\n\n

虽然 Postgres 中的任何事务都是原子的,但它不会阻止另一个(也是原子的)事务选择(并插入 - 或至少尝试)同一行,因为SELECT without FOR UPDATE不采用独占锁

\n\n

Postgres关于事务的手册

\n\n
\n

事务被认为是原子的:从其他事务的角度来看,它要么完全发生,要么根本不发生。

\n
\n\n

有关的:

\n\n\n\n
\n\n

澄清:

\n\n
    \n
  • 像这样的 SQL DML 命令INSERT始终自动是原子的,因为它不能在事务之外运行。但你不能说这INSERT 一笔交易。术语错误。

  • \n
  • 在 Postgres 中,所有锁都会保留到当前事务结束并在当前事务结束时释放。

  • \n
\n