假设我有多个工作人员可以同时读取和写入 MySQL 表(例如 jobs
)。每个 worker 的任务是:
- 找到最早的
QUEUED
作业 - 将其状态设置为
RUNNING
- 返回对应的ID。
请注意,当工作人员运行第 1 步时,可能不有任何符合条件的(即QUEUED
)作业。
到目前为止,我有以下伪代码。如果第 1 步未返回任何作业,我相信我需要取消 (ROLLBACK
) 事务。我将如何在下面的代码中做到这一点?
BEGIN TRANSACTION;
# Update the status of jobs fetched by this query:
SELECT id from jobs WHERE status = "QUEUED"
ORDER BY created_at ASC LIMIT 1;
# Do the actual update, otherwise abort (i.e. ROLLBACK?)
UPDATE jobs
SET status="RUNNING"
# HERE: Not sure how to make this conditional on the previous ID
# WHERE id = <ID from the previous SELECT>
COMMIT;
最佳答案
本周我正在实现与您的案例非常相似的事情。许多工作人员,每个工作人员都抓取一组行中的“下一个”行进行处理。
伪代码是这样的:
BEGIN;
SELECT ID INTO @id FROM mytable WHERE status = 'QUEUED' LIMIT 1 FOR UPDATE;
UPDATE mytable SET status = 'RUNNING' WHERE id = @id;
COMMIT;
使用FOR UPDATE
对于避免竞争条件很重要,即不止一个 worker 试图获取同一行。
参见 https://dev.mysql.com/doc/refman/8.0/en/select-into.html有关 SELECT ... INTO
的信息。
关于mysql - MySQL 中并发工作人员的原子读取和更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62394597/