Have “select for update” block on nonrexisting rows

前端 未结 3 606
深忆病人
深忆病人 2021-02-07 03:24

we have some persistent data in an application, that is queried from a server and then stored in a database so we can keep track of additional information. Because we do not wan

相关标签:
3条回答
  • 2021-02-07 03:28

    Example solution (i haven't found better :/)

    Thread A:

    BEGIN;
    SELECT pg_advisory_xact_lock(42); -- database semaphore arbitrary ID
    SELECT * FROM t WHERE id = 1;
    DELETE FROM t WHERE id = 1;
    INSERT INTO t (id, value) VALUES (1, 'thread A');
    SELECT 1 FROM pg_sleep(10); -- only for race condition simulation
    COMMIT;
    

    Thread B:

    BEGIN;
    SELECT pg_advisory_xact_lock(42); -- database semaphore arbitrary ID
    SELECT * FROM t WHERE id = 1;
    DELETE FROM t WHERE id = 1;
    INSERT INTO t (id, value) VALUES (1, 'thread B');
    SELECT 1 FROM pg_sleep(10); -- only for race condition simulation
    COMMIT;
    

    Causes always correct order of transactions execution.

    0 讨论(0)
  • 2021-02-07 03:28

    Looking at the code added in the second edit, it looks right.

    As for it looking like a hack, there's a couple options - basically it's all about moving the database logic to the database.

    One is simply to put the whole select for update, if not exist then insert logic in a function, and do select get_object(key1,key2,etc) instead.

    Alternatively, you could make an insert trigger that will ignore attempts to add an entry if it already exists, and simply do an insert before you do the select for update. This does have more potential to interfere with other code already in place, though.

    (If I remember to, I'll edit and add example code later on when I'm in a position to check what I'm doing.)

    0 讨论(0)
  • 2021-02-07 03:43

    I am not sure how select for update handles non-existing rows.

    It doesn't.

    The best you can do is to use an advisory lock if you know something unique about the new row. (Use hashtext() if needed, and the table's oid to lock it.)

    The next best thing is a table lock.

    That being said, your question makes it sound like you're locking way more than you should. Only lock rows when you actually need to, i.e. write operations.

    0 讨论(0)
提交回复
热议问题