mysql - MySQL 中并发工作人员的原子读取和更新

标签 mysql sql transactions

假设我有多个工作人员可以同时读取和写入 MySQL 表(例如 jobs)。每个 worker 的任务是:

  1. 找到最早的QUEUED 作业
  2. 将其状态设置为RUNNING
  3. 返回对应的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/

相关文章:

MYSQL:如何从表中删除所有键约束?

php - MySQL - 查找 JOINS 中记录的位置

hibernate - 连接池清空 Hibernate 4,但无法找到罪魁祸首

php - 如何限制此 MySQL 查询的结果?

mysql - 将csv文件导入mysql docker容器

mysql - 无法在 Concat select Prepared 语句中传递参数值

sql - 交易重复错误

MYSQL查询两个日期之间的数据,表没有日期列

javascript - 如何在php中从mysql数据库获取最后插入的id?

database - 数据库事务是在操作系统中管理内存的好方法吗?