How to lock row in mysql without blocking?

不想你离开。 提交于 2019-12-24 05:49:39

问题


I have a table in mariadb where I save links to some RSS feeds:

id | url                    | done
------------------------------------
 1 | http://example.com/rss | true
 2 | http://example.org/rss | false
 3 | http://google.com/rss  | false

When now one process/worker is updating one of the RSS feeds I want it to hide the row from other processes/workers so that they don't do the work twice and deadlock.

Using SELECT ... IN SHARE MODE or SELECT ... FOR UPDATE does not work as the row is still visible and will then be deadlocked by all other workers.

So the next idea was using a transaction which sets a flag on an additional locked column:

BEGIN;
    // find row and select its id
    SET @id := (SELECT id
    FROM url
    WHERE done = false
        AND locked = false
    LIMIT 1);

    // lock row by setting locked flag to true
    UPDATE url
    SET locked = true
    WHERE id = @id;

    // give us some time to copy and paste this sql in another console :)
    SELECT SLEEP(10);

    // unlock row and mark as done
    UPDATE url
    SET
        locked = false,
        done = true
    WHERE id = @id;
COMMIT;

Following SQL is executed over the sql package for Google Go.

This does work as intended but it works by blocking all other transactions. This means when I execute the above sql transaction into two sql consoles at the same time I can see how the later transaction waits for the first to finish. This effect destroys the complete idea of having multiple worker as they will be synced by the transaction in the end.

How can I "lock" a row from other transactions without blocking?


回答1:


You are using LOCK IN SHARE MODE which locks the row from UPDATE or DELETE operations, but allows the row to be read. Refer this documentation for more info. A brief from the documentation is below.

SELECT ... LOCK IN SHARE MODE sets a shared mode lock on any rows that are read. Other sessions can read the rows, but cannot modify them until your transaction commits.

For index records the search encounters, SELECT ... FOR UPDATE blocks other sessions from doing SELECT ... LOCK IN SHARE MODE or from reading in certain transaction isolation levels.

Your query returns the same row to all processes/workers and they simply wait for the previous lock to release before placing their own lock on the row. To accomplish the kind of lock you need, replace your SELECT ... LOCK IN SHARE MODE with SELECT ... FOR UPDATE.



来源:https://stackoverflow.com/questions/25718169/how-to-lock-row-in-mysql-without-blocking

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!