是不是PostgreSQL单个查询执行原子?

Isn't PostgreSQL single query execution atomic?

本问题已经有最佳答案,请猛点这里访问。

在我的PostgreSQL数据库中,我有一个表"我的表",列上有主键(A,B)。

我在下面为这个表中的插入编写了查询,以确保不会违反主键约束。

1
2
3
4
5
6
7
8
9
10
11
12
13
INSERT INTO my_table(a, b, c, d, e, f)
  (SELECT 'a1',
          'b1',
          'c1',
          1442849052013,
          1,
          FALSE
   FROM
     (SELECT 'a1'::VARCHAR(100) AS a,
             'b1'::VARCHAR(50) AS b) AS new_fields
   LEFT OUTER JOIN my_table AS old_fields ON (new_fields.a = old_fields.a
                                              AND new_fields.b = old_fields.b)
   WHERE old_fields.a IS NULL);

当多个这样的查询被并发运行的线程激发时,我有时会

PSQLException: duplicate key value violates unique constraint
"my_table_pkey". Detail: Key (a, b)=(a1, b1) already exists.

我无法理解此查询如何导致指定的错误条件,因为只有在缺少主键列并且正在同一查询中检查此条件的情况下,此查询才会插入"我的表"。

如果这是一个有效的场景,这是否意味着PostgreSQL中的查询执行不是原子的?

有人能解释一下…

在这里,select for update语法将不起作用,因为select for update会锁定选定的行,如果该行不存在,我希望插入该行。


PostgreSQL中的默认事务隔离级别read committed没有看到任何未提交的数据。

因此,如果另一个未提交的事务已插入("A1"、"B1"),则其他事务将看不到它。

但是,约束的存在将确保在第一个事务回滚(并且您的事务可以成功完成)或提交(并且您的事务将因违反约束而失败)之前,另一个事务尝试插入("a1"、"b1")的操作无法完成。

文件中有完整的解释。