我有一个表由不同的线程同时读取。
每个线程必须选择100行,在每行上执行一些任务(与数据库无关),然后他们必须从表中删除所选行。
使用此查询选择行:
SELECT id FROM table_name FOR UPDATE;
我的问题是:如何忽略(或跳过)先前在MySQL中使用select语句锁定的行?
答案 0 :(得分: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;
确保每个线程从表中选择一组唯一的行。
希望这有帮助。
答案 1 :(得分: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
为事务设置一个小超时,如果该行被锁定,则事务被中止,我尝试另一个。如果我获得了锁,我会处理它。如果(运气不好)该行被锁定,它会被处理并且在我的超时之前释放锁,然后我选择一个已被“处理”的行!但是,我检查了我的进程设置的字段(例如状态):如果其他进程事务结束正常,该字段告诉我工作已经完成,我不再处理该行。
没有事务的每个其他可能的解决方案(例如,如果行没有状态设置另一个字段等等)可以轻松提供竞争条件和错过的进程(例如,一个线程突然死亡,分配的数据仍然被标记,而交易到期;参考评论here
希望有所帮助