MySQL 多个消费者怎么用 SKIP LOCKED 领取任务
多个消费者共同读取 MySQL 任务表时,核心写法是把领取动作放进短事务:先用 SELECT ... FOR UPDATE SKIP LOCKED 锁定一条待处理任务,再在同一事务里把它改成 processing,最后提交。其他消费者遇到这条已锁记录会直接跳过,继续尝试下一条,而不是排队等待。
SKIP LOCKED适合队列式表,不适合要求完整一致视图的普通查询。- 领取和状态更新必须在同一个 InnoDB 事务中,提交后再执行耗时业务。
- 没有任务、消费者崩溃、复制模式和长任务超时,都要有明确的恢复策略。
先把任务表设计成可并发领取
先准备一个状态清晰、能快速筛选的队列表。下面的字段足够演示领取路径,生产环境还可以增加重试次数、租约截止时间和错误摘要。
CREATE TABLE task_queue (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
payload JSON NOT NULL,
status ENUM('pending', 'processing', 'done', 'failed') NOT NULL DEFAULT 'pending',
claimed_by VARCHAR(64) NULL,
claimed_at DATETIME NULL,
PRIMARY KEY (id),
KEY idx_queue_status_id (status, id) -- 让领取条件和排序共享索引
) ENGINE = InnoDB;
status, id 联合索引对应 WHERE status = 'pending' ORDER BY id。它不是为了保证绝对公平,而是让消费者有稳定的扫描顺序;被锁住的旧任务会被跳过,后面的任务可以先被领取。
| 字段或条件 | 作用 | 领取时的判断 |
|---|---|---|
status | 表达任务生命周期 | 只选择 pending |
id | 稳定排序和唯一定位 | 领取后用主键更新 |
claimed_by | 记录消费者身份 | 便于审计与排障 |
claimed_at | 记录租约或超时起点 | 恢复卡住任务时使用 |

在短事务里用 FOR UPDATE SKIP LOCKED 抢一条
每个消费者都要使用自己的数据库连接,并显式开启事务。锁定读只有在事务未提交时才有意义;如果开启自动提交,锁可能在语句结束时就释放,领取和标记就无法形成一个原子动作。
START TRANSACTION;
-- 只找待处理且当前没有被其他消费者锁住的任务
SELECT id, payload
FROM task_queue
WHERE status = 'pending'
ORDER BY id
LIMIT 1
FOR UPDATE SKIP LOCKED;
-- 应用拿到 id 后,在同一事务内完成状态转移
UPDATE task_queue
SET status = 'processing',
claimed_by = 'worker-a',
claimed_at = NOW()
WHERE id = 12345
AND status = 'pending'; -- 防止状态已经变化时误更新
COMMIT; -- 提交后才释放领取锁
应用层要检查查询是否返回了行,以及 UPDATE 的影响行数。查询没有结果时说明当前没有可领取任务,可以短暂退避后重试;不要把它当成异常死循环。两个消费者同时执行时,已被第一个事务锁住的记录会从第二个结果集中消失,但第二个消费者仍可能读到更靠后的任务。
MySQL 官方说明了这个语义:SKIP LOCKED 不等待行锁,直接从结果集中移除被锁行;因此返回的是不一致视图,只适合队列一类允许跳过锁行的场景。它只对行级锁生效,使用语句复制时还要单独评估安全性。
把数据库领取和业务执行分开
不要在事务里调用远程 API、生成文件或执行几分钟的业务。正确边界是“短事务只负责认领,提交后再处理”:任务进入 processing 后,消费者可以在事务外完成工作,成功后更新为 done,失败则写入 failed 或增加重试次数。
进程在提交前崩溃,事务回滚,任务仍是 pending;进程在提交后、业务完成前崩溃,任务可能停留在 processing。后一种情况不能依赖锁自动解决,应结合 claimed_at 做租约超时恢复,并让业务操作具备幂等性。否则恢复消费者可能再次执行已经完成一半的外部动作。

上线前检查这几项并发边界
- 确认表使用 InnoDB,查询条件包含明确的
ORDER BY和LIMIT,并检查(status, id)索引。 - 确认每次领取都显式提交或回滚;连接归还连接池前不能留下未结束事务。
- 为空队列设置退避,死锁或瞬时连接错误采用有限次数重试。
- 为
processing任务保存领取者和时间,定时恢复超时租约。 - 把外部副作用设计成幂等,并根据部署环境评估复制方式和锁等待监控。
常见问题
SKIP LOCKED 会保证任务严格按 id 顺序处理吗?
不会。它只提供“遇到已锁行就跳过”的并发行为,后面的任务可能先完成。需要严格顺序时,应改用单消费者、分区队列或业务层排序。
查询不到任务时应该回滚吗?
如果已经开启事务,建议回滚或提交后再退避,确保连接没有留下未结束事务。空结果本身不是数据库错误。
为什么任务状态已经是 processing,却仍然重复执行?
通常是消费者在提交领取后崩溃,恢复逻辑又重新拿走了超时任务。需要租约、尝试次数和幂等键一起控制,而不是只依赖状态字段。
可以用普通 SELECT 再 UPDATE 代替吗?
不建议。普通读取和更新之间存在竞争窗口,多个消费者可能读到同一行;要么使用锁定读,要么采用带条件的原子更新并设计清晰的重试结果。
因此,MySQL 多消费者队列的最小可靠组合是:InnoDB、短事务、FOR UPDATE SKIP LOCKED、同事务状态更新,以及事务外的幂等执行和超时恢复。
BATOTO漫画要注册吗?免费模式、广告与隐私边界说明
- 上一篇
- BATOTO漫画要注册吗?免费模式、广告与隐私边界说明
- 下一篇
- Go 为什么不能直接修改 map 里结构体的字段
-
- 数据库 · MySQL | 1分钟前 | MySQL · SQL · GROUP_CONCAT · mysql group_concat group_concat_max_len
- MySQL GROUP_CONCAT 结果被截断怎么处理
- 470浏览 收藏
-
- 数据库 · MySQL | 2小时前 | MySQL · 索引优化 · generated-column · mysql 索引 生成列 计算字段
- MySQL 怎么用生成列保存可索引的计算结果
- 297浏览 收藏
-
- 数据库 · MySQL | 7小时前 |
- MySQL LEFT JOIN 怎么统计数量并保留零记录
- 477浏览 收藏
-
- 数据库 · MySQL | 8小时前 | SQL查询 · 子查询 · MySQL教程 · NULL判断 · mysql NOT IN NOT EXISTS
- MySQL NOT IN 查不到数据是不是 NULL 导致的
- 413浏览 收藏
-
- 数据库 · MySQL | 9小时前 |
- MySQL 按天统计怎么补齐没有数据的日期
- 177浏览 收藏
-
- 数据库 · MySQL | 11小时前 | MySQL · JSON查询 · JSON_TABLE · mysql JSON数组 JSON_TABLE
- MySQL JSON 数组怎么展开成多行查询
- 490浏览 收藏
-
- 数据库 · MySQL | 22小时前 | MySQL · SQL查询 · ROW_NUMBER · mysql group by 分组查询 ROW_NUMBER
- MySQL 分组后怎么取每组最新一条记录
- 423浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL 第几万页开始变慢:用稳定排序和游标条件替代深 OFFSET
- 405浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 161次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 88次使用
-
- ClickPrompt
- ClickPrompt是一款专为AI提示词编写者设计的开源在线工具,支持Stable Diffusion绘图、ChatGPT对话及GitHub Copilot代码辅助。提供Prompt自动生成、一键运行、社区分享及可视化优化功能,帮助用户高效获取精准AI输出。
- 48次使用
-
- PromptHero
- PromptHero是专业的AI提示词搜索引擎与优化平台,支持Stable Diffusion、Midjourney等主流模型。提供海量提示词库、分类搜索、在线课程及社区互动,助力用户高效生成高质量AI图像与文本。
- 30次使用
-
- Stable Diffusion Prompt Book
- 深入解析OpenArt推出的Stable Diffusion Prompt Book,这本免费的开源提示词指南涵盖从基础语法到高级技巧,提供风格化词库与参数建议,助您优化AI绘画生成效果。
- 33次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览
-
- Go语言实现操作MySQL的基础知识总结
- 2023-01-23 265浏览

