代码之家  ›  专栏  ›  技术社区  ›  Steven Schlansker

主键上的PostgreSQL插入由于争用而失败,甚至在可序列化级别也是如此。

  •  3
  • Steven Schlansker  · 技术社区  · 14 年前

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

    当您设置一个值时,如果键不在,我希望它插入,否则更新。遗憾的是,Postgres没有insert或update语句,因此我必须自己模拟它。

    我一直致力于 SELECT 确定密钥是否存在,然后运行相应的 INSERT UPDATE . 现在很明显,这需要发生在一个交易中,或者所有的坏事都可能发生。

    但是,这并不是我想要的工作方式——我知道序列化事务有局限性,但我不确定如何解决这个问题。

    情况是这样的-

    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 回复  |  直到 13 年前
        1
  •  2
  •   Kornel    13 年前

    之前 Postgres 9.1 隔离存在问题:

    请求可序列化的隔离只保证整个事务使用一个MVCC快照,这允许某些记录的异常。

    也许你碰到了这些“异常”。

    你可以试试 SELECT … FOR UPDATE 检查行是否存在时。

    或者, LOCK TABLE 你自己。

    如果您试图实现upsert,那么一种更可靠(或更不可靠)的方法是首先尝试更新,检查受影响的行数,然后在没有更新行的情况下尝试插入。