如果稍后查询失败,WITH 会发生什么

Rou*_*ouz 4 postgresql cte transaction

我绝不是数据库专家,所以我可能会问一些愚蠢的问题。

所以我正在使用 PostgreSQL,我想对一个表进行插入,保留 ID(ID 自动递增)并将一个元组插入另一个表(元组中有该 ID)。

显然我想让事情保持原子性。

询问:

WITH inserted AS (
  INSERT INTO
    "public"."user" (email, first_name, last_name, username)
  VALUES
    (?, ?, ?, ?)
  RETURNING id
)
INSERT INTO 
  "public"."security" (user_id, security)
VALUES((
  SELECT id FROM inserted
), ?);
Run Code Online (Sandbox Code Playgroud)

问题是,这甚至可以工作吗?如果第二次插入失败会发生什么?第一个会坚持下去吗?

显而易见的答案是,我可能会将其放入事务并提交/回滚,但这是否足够?

a_h*_*ame 7

单个语句始终以原子方式运行。

从手册中引用

PostgreSQL 实际上将每个 SQL 语句视为在事务中执行。如果您不发出 BEGIN 命令,则每个单独的语句都有一个隐式 BEGIN 和(如果成功)围绕它的 COMMIT。由 BEGIN 和 COMMIT 包围的一组语句有时称为事务块

在同一WITH子句下定义的一组公用表表达式,无论它们中有多少(包括可写 CTE),仍然是单个语句的一部分。

所以该语句要么完全失败,要么完全成功。

如果您想以原子方式运行多个语句,则只需要(显式)事务。

生成的序列值的处理与任何其他情况没有什么不同:nextval 操作永远不会回滚