Select unlocked row in Postgresql

后端 未结 14 2055
你的背包
你的背包 2020-12-13 06:20

Is there a way to select rows in Postgresql that aren\'t locked? I have a multi-threaded app that will do:

Select... order by id desc limit 1 for update


        
相关标签:
14条回答
  • 2020-12-13 06:34

    Used in multi-thread and cluster?
    How about this?

    START TRANSACTION;
    
    // All thread retrive same task list
    // If result count is very big, using cursor 
    //    or callback interface provied by ORM frameworks.
    var ids = SELECT id FROM tableName WHERE k1=v1;
    
    // Each thread get an unlocked recored to process.
    for ( id in ids ) {
       var rec = SELECT ... FROM tableName WHERE id =#id# FOR UPDATE NOWAIT;
       if ( rec != null ) {
        ... // do something
       }
    }
    
    COMMIT;
    
    0 讨论(0)
  • 2020-12-13 06:37

    Looks like you're looking for a SELECT FOR SHARE.

    http://www.postgresql.org/docs/8.3/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE

    FOR SHARE behaves similarly, except that it acquires a shared rather than exclusive lock on each retrieved row. A shared lock blocks other transactions from performing UPDATE, DELETE, or SELECT FOR UPDATE on these rows, but it does not prevent them from performing SELECT FOR SHARE.

    If specific tables are named in FOR UPDATE or FOR SHARE, then only rows coming from those tables are locked; any other tables used in the SELECT are simply read as usual. A FOR UPDATE or FOR SHARE clause without a table list affects all tables used in the command. If FOR UPDATE or FOR SHARE is applied to a view or sub-query, it affects all tables used in the view or sub-query.

    Multiple FOR UPDATE and FOR SHARE clauses can be written if it is necessary to specify different locking behavior for different tables. If the same table is mentioned (or implicitly affected) by both FOR UPDATE and FOR SHARE clauses, then it is processed as FOR UPDATE. Similarly, a table is processed as NOWAIT if that is specified in any of the clauses affecting it.

    FOR UPDATE and FOR SHARE cannot be used in contexts where returned rows cannot be clearly identified with individual table rows; for example they cannot be used with aggregation.

    0 讨论(0)
  • 2020-12-13 06:37

    What are you trying to accomplish? Can you better explain why neither unlocked row updates nor full transactions will do what you want?

    Better yet, can you prevent contention and simply have each thread use a different offset? This won't work well if the relevant portion of the table is being updated frequently; you'll still have collisions but only during heavy insert load.

    Select... order by id desc offset THREAD_NUMBER limit 1 for update
    
    0 讨论(0)
  • 2020-12-13 06:38

    My solution is to use the UPDATE statement with the RETURNING clause.

    Users
    
    -----------------------------------
    ID        | Name       |      flags
    -----------------------------------
    1         |  bob       |        0  
    2         |  fred      |        1  
    3         |  tom       |        0   
    4         |  ed        |        0   
    

    Instead of SELECT .. FOR UPDATE use

    BEGIN; 
    
    UPDATE "Users"
    SET ...
    WHERE ...;
    RETURNING ( column list );
    
    COMMIT;
    

    Because the UPDATE statement obtains a ROW EXCLUSIVE lock on the table its updating you get serialized updates. Reads are still allowed, but they only see data before the start of the UPDATE transaction.

    Reference: Concurrency Control Chapter of Pg docs.

    0 讨论(0)
  • 2020-12-13 06:38

    Since I haven't found a better answer yet, I've decided to use locking within my app to synchronize access to the code that does this query.

    0 讨论(0)
  • 2020-12-13 06:40

    This feature, SELECT ... SKIP LOCKED is being implemented in Postgres 9.5. http://www.depesz.com/2014/10/10/waiting-for-9-5-implement-skip-locked-for-row-level-locks/

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