我已经完成了几乎所有类似的问题,但没有找到我的问题的答案。很抱歉,如果我错过了已经发布的问题,那么我会回答这个问题。
我有一个MySQL表,我将其用作作业队列。有多个工作人员从这些表中读取工作。
挑战在于如何使用桌面上的MySQL查询来实现这一目标。
我必须选择行并同时更新作业状态。这应该是自动的,因此没有工人获得已处理的工作。
我想自动运行(伪代码):
select name, job_type from jobs where job_status = "created" limit 10;
foreach row {
update table jobs set job_status = "processing" where id = '$id';
}
这是否可以在MySQL中使用查询/存储过程/游标?
答案 0 :(得分:0)
我相信这是您案件的解决方案:
update jobs set job_status = "processing"
where id = '$id'
and job_status = "created"
答案 1 :(得分:0)
这些技术依赖于事务,因此请确保自动提交已关闭。出于性能和数据完整性的原因,您无论如何都不应该使用自动提交。
这也依赖于使用InnoDB表格式。 MyISAM不支持行级锁定。
使用SELECT ... FOR UPDATE
对返回的行进行独占锁定。在事务提交或回滚之前,锁将保持不变。
select id, name, job_type
from jobs
where job_status = "created"
limit 10
for update;
foreach row {
update table jobs set job_status = "processing" where id = '$id';
...process...
delete from jobs where id = '$id';
}
commit
除非你有充分的理由这样做,否则你最好一次只抓一排。这是一个简单,快速的查询,没有理由坚持10.实际上,如果你保持10,你就不能在每次成功的工作之后提交。
select id, name, job_type
from jobs
where job_status = "created"
limit 1
for update;
update table jobs set job_status = "processing" where id = '$id';
...process the job...
delete from jobs where id = '$id';
commit
我们可以进一步削减它。没有必要将工作设置为处理,其他交易无论如何都不会看到更改。我们可以依靠独家锁。
select id, name, job_type
from jobs
where job_status = "created"
limit 1
for update;
...process $id...
delete from jobs where id = '$id';
commit
这很强大。如果您的工作人员崩溃,其锁定将被删除,另一名工作人员可以再次尝试该工作。
或者,您可以一次更新一个。这需要getting the ID of the row you just updated。
SET @update_id := 0;
UPDATE jobs
SET job_status = "processing", id = (SELECT @update_id := id)
WHERE job_status = "created"
LIMIT 1;
SELECT @update_id;
...do work on @update_id...
DELETE FROM jobs WHERE id = @update_id
COMMIT
这依赖于UPDATE setting an exclusive lock on each updated row,其他交易将无法更新该行。这就是为什么一次一个工作的好主意。
或者,添加queued
作业状态以及哪个进程拥有它。
UPDATE jobs
SET job_status = "queued", job_owner = "$pid"
WHERE job_status = "created" limit 10;
COMMIT;
SELECT name, job_type
FROM jobs
WHERE job_status = "queued"
AND job_owner = "$pid"
foreach row {
UPDATE jobs SET job_status = "processing" where id = '$id';
... process ...
DELETE FROM jobs WHERE id = '$id';
COMMIT;
}
这种方法的缺点是,如果工人死亡,它仍将拥有工作。如果你有一个长寿命的主人控制队列并将工作分配给工人,我只会推荐这种方法。
最后,有subtle problems with using MySQL as a queue。考虑获得真正的排队服务。