主键上的PostgreSQL插入失败,即使在可序列化级别也存在争用

时间:2010-05-20 01:33:44

标签: postgresql transactions

我正在尝试在PostgreSQL数据库中插入或更新数据。最简单的情况是键值配对(实际数据更复杂,但这是最小的明显例子)

设置值时,如果键不存在,我希望插入,否则更新。可悲的是Postgres没有插入或更新声明,所以我必须自己模仿它。

我一直在研究基本SELECT密钥是否存在的想法,然后运行相应的INSERTUPDATE。现在显然,这需要处于交易中,或者可能发生各种不良事件。

然而,这并不是我想要的方式 - 我明白可序列化交易存在限制,但我不知道如何解决这个问题。

情况如下 -

ab: => set transaction isolation level serializable;
a:  => select count(1) from table where id=1; --> 0
b:  => select count(1) from table where id=1; --> 0
a:  => insert into table values(1); --> 1
b:  => insert into table values(1); --> 
    ERROR:  duplicate key value violates unique constraint "serial_test_pkey"

现在我希望它抛出通常的“由于并发更新而无法提交”,但我猜测因为插入不同的“行”这不会发生。

有一种简单的方法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:2)

Postgres 9.1之前,存在隔离问题:

  

要求可序列化隔离仅保证单个MVCC快照将用于整个事务,这允许某些记录的异常。

也许你正在遇到这些“异常现象”。

检查行是否存在时,您可以尝试SELECT … FOR UPDATE

或者,LOCK TABLE自己。

如果您正在尝试实施UPSERT,那么稍微更可靠(或者更不可靠)的方法是首先尝试UPDATE,检查受影响的行数,然后在没有更新行的情况下尝试INSERT。