Is SELECT or INSERT in a function prone to race conditions?

前端 未结 3 1119
伪装坚强ぢ
伪装坚强ぢ 2020-11-22 07:29

I wrote a function to create posts for a simple blogging engine:

CREATE FUNCTION CreatePost(VARCHAR, TEXT, VARCHAR[])         


        
3条回答
  •  盖世英雄少女心
    2020-11-22 07:42

    There's still something to watch out for even when using the ON CONFLICT clause introduced in Postgres 9.5. Using the same function and example table as in @Erwin Brandstetter's answer, if we do:

    Session 1: begin;
    
    Session 2: begin;
    
    Session 1: select f_tag_id('a');
     f_tag_id 
    ----------
           11
    (1 row)
    
    Session 2: select f_tag_id('a');
    [Session 2 blocks]
    
    Session 1: commit;
    
    [Session 2 returns:]
     f_tag_id 
    ----------
            NULL
    (1 row)
    

    So f_tag_id returned NULL in session 2, which would be impossible in a single-threaded world!

    If we raise the transaction isolation level to repeatable read (or the stronger serializable), session 2 throws ERROR: could not serialize access due to concurrent update instead. So no "impossible" results at least, but unfortunately we now need to be prepared to retry the transaction.

    Edit: With repeatable read or serializable, if session 1 inserts tag a, then session 2 inserts b, then session 1 tries to insert b and session 2 tries to insert a, one session detects a deadlock:

    ERROR:  deadlock detected
    DETAIL:  Process 14377 waits for ShareLock on transaction 1795501; blocked by process 14363.
    Process 14363 waits for ShareLock on transaction 1795503; blocked by process 14377.
    HINT:  See server log for query details.
    CONTEXT:  while inserting index tuple (0,3) in relation "tag"
    SQL function "f_tag_id" statement 1
    

    After the session that received the deadlock error rolls back, the other session continues. So I guess we should treat deadlock just like serialization_failure and retry, in a situation like this?

    Alternatively, insert the tags in a consistent order, but this is not easy if they don't all get added in one place.

提交回复
热议问题