0

我正在将 Spring 与 PostgreSQL 一起使用,并尝试通过使用如下代码来执行一种 UPSERT:

jt.update("delete from A where id = 1")
jt.update("insert into A (id, value) values (1, 100)")

包裹在事务中(使用@Transactional)。

问题是,当有许多并发请求时,此代码会因“重复键”错误而失败,这意味着事务不是孤立的,或者......

我是否错过了有关交易如何运作的一些信息?我应该在这里使用不同的机制(例如线程同步)吗?

4

2 回答 2

11

我写了一篇关于它的相当大的博文,所以即使我可能会因为链接而被否决,请阅读这篇文章。

要点是事务在这里没有帮助(至少在默认情况下),虽然可以编写正确的 upsert,但实际上非常棘手。

于 2013-06-17T17:03:53.660 回答
5

假设这个简单的表:

CREATE TABLE tbl(id int primary key, value int);

对于并发事务,此功能几乎100% 安全(请参阅评论)。:

CREATE OR REPLACE FUNCTION f_upsert(_id int, _value int)
  RETURNS void AS
$func$
BEGIN
LOOP
   UPDATE tbl SET value = _value WHERE  id = _id;

   EXIT WHEN FOUND;

   BEGIN
      INSERT INTO tbl (id, value)
      VALUES (_id, _value);

      RETURN;

   EXCEPTION WHEN UNIQUE_VIOLATION THEN     -- tbl.id has UNIQUE constraint.
      RAISE NOTICE 'It actually happened!'; -- hardly ever happens
   END;

END LOOP;
END
$func$ LANGUAGE plpgsql;

称呼:

SELECT f_upsert(2, 2);

它与这个案例非常相似,INSERT / SELECT有更多的解释和链接:

于 2013-06-17T17:29:47.987 回答