忽略 MySQL 查询中锁定的行

问题描述 投票:0回答:3

我有一张表,由不同的线程同时读取。

每个线程必须选择 100 行,对每行执行一些任务(与数据库无关),然后必须从表中删除所选行。

使用此查询选择行:

SELECT id FROM table_name FOR UPDATE;

我的问题是:如何忽略(或跳过)之前在 MySQL 中使用 select 语句锁定的行?

mysql locking race-condition
3个回答
15
投票

我通常创建一个默认为 NULL 的 process_id 列,然后让每个线程使用唯一标识符来执行以下操作:

UPDATE table_name SET process_id = #{process.id} WHERE process_id IS NULL LIMIT 100;

SELECT id FROM table_name WHERE process_id = #{process.id} FOR UPDATE;

这确保每个线程从表中选择一组唯一的行。

希望这有帮助。


0
投票

尽管这不是最好的解决方案,因为我无法知道忽略锁定的行,但我选择随机一个并尝试获取锁定。

START TRANSACTION;
SET @v1 =(SELECT myId FROM tests.table WHERE status is NULL LIMIT 1);
SELECT * FROM tests.table WHERE myId=@v1 FOR UPDATE; #<- lock

为事务设置一个小的超时,如果该行被锁定,则事务将中止,然后我尝试另一行。如果我获得了锁,我就会处理它。如果(运气不好)该行被锁定,它会被处理并在超时之前释放锁,然后我选择一个已经被“处理”的行!但是,我检查我的流程设置的字段(例如状态):如果其他流程事务正常结束,该字段告诉我工作已经完成,我不会再次处理该行。

没有事务的所有其他可能的解决方案(例如,如果行没有状态等,则设置另一个字段等)可以轻松提供竞争条件和错过的进程(例如,一个线程突然死亡,分配的数据仍然被标记,而事务过期;参考评论这里

希望有帮助


0
投票

从 8.0.1 版本开始,Mysql 现在有 SKIP LOCKED 和 NOWAIT。顾名思义,在获取锁定时,它会忽略是否存在已锁定的行。

这个博客很好地捕捉到了这一点。

© www.soinside.com 2019 - 2024. All rights reserved.