Upsert with a transaction

前端 未结 2 1510
耶瑟儿~
耶瑟儿~ 2020-12-02 03:00

I\'m using Spring with PostgreSQL and I try to do a sort of UPSERT by using a code like this:

jt.update(\"delete from A where id = 1\")
jt.update(\"insert in         


        
相关标签:
2条回答
  • 2020-12-02 03:49

    I wrote a rather large blogpost about it, so even though I might get downvotes for links, read this.

    The gist is that transactions do not help in here (at least by default), and while it is possible to write correct upsert, it's actually pretty tricky.

    0 讨论(0)
  • 2020-12-02 03:52

    Assuming this simple table:

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

    This function almost 100% secure (see comments) for concurrent transactions.:

    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;
    

    Call:

    SELECT f_upsert(2, 2);
    

    It's very similar to this INSERT / SELECT case with more explanation and links:

    • Is SELECT or INSERT in a function prone to race conditions?
    0 讨论(0)
提交回复
热议问题