MySQL for update skip locked 与 for update nowait

server/2024/12/27 4:16:50/

理论(下方有实操)

for update skip locked

  • 官方文档:https://dev.sql>mysql.com/doc/refman/8.0/en/innodb-locking-reads.html#innodb-locking-reads-for-update
  • 语法:select语句后跟 for update skip locked
  • 作用:目标对象没有被其它会话加锁则可加锁,被其它会话加了锁就跳过。
  • 解决问题:用来避免锁资源竞争引起的阻塞。
  • 适用场景:
    • 多用于MySQL作为消息队列的存储组件,特别是消费者数量>1的场景,多个worker进程同时检测任务队列中的任务,确保每个任务只被一个worker处理,同时其它worker不会被阻塞(这里的worker进程,可以是不断循环查询队列任务的过程,用毫秒级到分钟级的死循环检测表里是否有要处理的队列任务,加锁是为了避免多个消费者同时处理同一个队列任务引发的并发问题)。
    • 换句话说:加锁的目的是为了避免多个消费者同时消费相同的数据造成重复消费,加skip locked的目的是为了保证其它进程每次扫描到加锁的数据时跳开,避免因排它锁阻塞,保证探测任务快速执行。
  • 坑:
    • 不适用与并发条件下加锁保证数据不出错的场景,因为它遇见目标数据加锁就跳过。(MySQL官方文档原文:Queries that skip locked rows return an inconsistent view of the data. SKIP LOCKED is therefore not suitable for general transactional work. However, it may be used to avoid lock contention when multiple sessions access the same queue-like table.)。
    • 它能跳过仅仅是它能跳过,不代表没加skip locked的X或S锁遇见这个锁不会发生阻塞。
    • MySQL8才有的特性,5.7会报错:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘skip locked’ at line 1。

nowait

  • 官方文档:https://dev.sql>mysql.com/doc/refman/8.0/en/innodb-locking-reads.html#innodb-locking-reads-for-update
  • 语法:select语句后跟 nowait。
  • 作用:目标对象没有被其它会话加锁则可加锁,被其它会话加了锁则返回异常。
  • 解决问题:用来避免锁资源竞争引起的阻塞。
  • 适用场景:类似于skip locked,但应用场景不多,因为MySQL返回的异常,可能会升级为编程语言调用时的报错。
  • 坑:MySQL8才有的特性,5.7会报错:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘nowait’ at line 1。

No BB,Show Code

成品用例

  • 以消息队列表为例,这是一个标准的支持多渠道,多生产者,多消费者队列和延时队列的任务记录表(记录失败的任务表需要另创建,本文略)。
sql">CREATE TABLE `jobs` (`id` bigint unsigned NOT NULL AUTO_INCREMENT,`queue` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '不同渠道队列执行的优先级,可以是high,default,low等。',`payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '队列进程所需要的数据,序列化后的json字符串,包含了框架所需要的序列化数据和业务数据。',`attempts` tinyint unsigned NOT NULL COMMENT '记录任务已经被尝试执行的次数。每次任务失败后,attempts的值会递增。当attempts达到设定的最大重试次数时,任务将被标记为失败。',`reserved_at` int unsigned DEFAULT NULL COMMENT '表示任务被锁定(reserved)的时间戳。当一个worker开始处理任务时,任务会被锁定,以防止其它 worker同时处理相同的任务。reserved_at存储的是记录被锁定时的时间戳。',`available_at` int unsigned NOT NULL COMMENT '记录任务应该变为可执行状态的时间戳。将任务推送到队列时,可以选择延迟任务的执行时间。',`created_at` int unsigned NOT NULL COMMENT '队列被创建的时间戳。',PRIMARY KEY (`id`) USING BTREE,KEY `jobs_queue_index` (`queue`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
  • 添加三条模拟数据,新增了3个队列任务
sql">INSERT INTO `jobs` (`id`, `queue`, `payload`, `attempts`, `reserved_at`, `available_at`, `created_at`) VALUES (1, 'default', '这里是要被处理的任务:xxxxx', 1, NULL, 1735097169, 1735097169);
INSERT INTO `jobs` (`id`, `queue`, `payload`, `attempts`, `reserved_at`, `available_at`, `created_at`) VALUES (2, 'default', '这里是要被处理的任务:xxxxx', 1, NULL, 1735097179, 1735097179);
INSERT INTO `jobs` (`id`, `queue`, `payload`, `attempts`, `reserved_at`, `available_at`, `created_at`) VALUES (3, 'default', '这里是要被处理的任务:xxxxx', 1, NULL, 1735097189, 1735097189);
  • 队列在无任务执行时的扫描任务,SQL是这样的,找到符合条件的数据后更新reserved_at字段为当前时间,并使用worker进程执行队列任务。
sql">select * from `jobs` where `queue` = 'high' and ((`reserved_at` is null and `available_at` <= 1735097879) or (`reserved_at` <= 1735094259)) order by `id` asc limit 1 FOR UPDATE SKIP LOCKED  
select * from `jobs` where `queue` = 'default' and ((`reserved_at` is null and `available_at` <= 1735097879) or (`reserved_at` <= 1735094259)) order by `id` asc limit 1 FOR UPDATE SKIP LOCKED  
select * from `jobs` where `queue` = 'low' and ((`reserved_at` is null and `available_at` <= 1735097879) or (`reserved_at` <= 1735094259)) order by `id` asc limit 1 FOR UPDATE SKIP LOCKED

for update skip locked用法

证明跳过被锁定的行

步骤会话1会话2说明
1start transaction;start transaction;双方开启事务
2select * from jobs where queue = ‘default’ and ((reserved_at is null and available_at <= 1735097879) or (reserved_at <= 1735094259)) order by id asc limit 1 FOR UPDATE SKIP LOCKED/会话1返回id为1的数据
3/select * from jobs where queue = ‘default’ and ((reserved_at is null and available_at <= 1735097879) or (reserved_at <= 1735094259)) order by id asc limit 1 FOR UPDATE SKIP LOCKED会话2返回id为2的数据,直接跳过加锁的1
4update jobs set reserved_at = UNIX_TIMESTAMP() where id = 1;update jobs set reserved_at = UNIX_TIMESTAMP() where id = 2;将找到的任务标记为队列正在处理
5commit;commit;提交事务,结束流程

nowait用法

证明锁定相同范围的数据会报错。

步骤会话1会话2说明
1start transaction;start transaction;双方开启事务
2select * from jobs where id = 3 FOR UPDATE nowait;/可正常加锁
3/select * from jobs where id = 3 FOR UPDATE nowait;报错:3572 - Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.
4commit;commit;提交事务,结束流程

http://www.ppmy.cn/server/153519.html

相关文章

面试题整理(四)

1.Max transition,leakage优化,hold time ,setup time violation修复的顺序是? 答:先把max transition修复掉,如果max transition有violation,意味着其超出了查找表范围之外,所以计算得到的delay都不是很准的。 其次是把setup修复了,因为setup相对来说,需要减少cell…

Nginx单向链表 ngx_list_t

目录 基本概述 数据结构 接口描述 具体实现 ngx_list_create ngx_list_init ngx_list_push 使用案例 整理自 nginx 1.9.2 源码 和 《深入理解 Nginx&#xff1a;模块开发与架构解析》 基本概述 Nginx 中的 ngx_list_t 是一个单向链表容器&#xff0c;链表中的每一个节…

iOS AccentColor 和 Color Set

AccentColor 和 Color Set 都是 Xcode 中用于颜色管理的功能&#xff0c;它们适用于不同的开发场景和需求。以下是它们的区别和应用场景分析&#xff1a; 1. AccentColor&#xff08;强调色&#xff09; 1.1 概念&#xff1a; • AccentColor 是在 Xcode 12 中引入的&#xf…

【Select 语法全解密】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录前言一、Select 执行位置二、返回一个字段和多个字段三、单表返回DTO四、多表返回DTO4.1 手动DTO4.2 实体自动映射14.…

【解决报错】AttributeError: ‘NoneType‘ object has no attribute ‘group‘

学习爬虫时&#xff0c;遇到如下报错&#xff1a; 报错原因&#xff1a; 正则表达式的 search 或 finditer 方法没有找到任何匹配项&#xff0c;可能是换行符处理不当等。 解决方法如下&#xff1a; 在正则表达式末尾加上re.S即可&#xff0c;re.S是一个编译标志&#xff0c…

Milvus矢量数据库 麒麟v10安装

什么是Milvus矢量数据库&#xff1f; Milvus 创建于 2019 年&#xff0c;其目标只有一个&#xff1a;存储、索引和管理由深度神经网络和其他机器学习 (ML) 模型生成的海量嵌入向量。 作为专门设计用于处理对输入向量的查询的数据库&#xff0c;它能够对一万亿级的向量进行索引…

青少年编程与数学 02-004 Go语言Web编程 15课题、表单处理

青少年编程与数学 02-004 Go语言Web编程 15课题、表单处理 一、表单二、表单处理步骤 1: 创建表单&#xff08;HTML&#xff09;步骤 2: 编写表单处理函数&#xff08;Go&#xff09; 三、重要性 课题摘要:本文讨论了Web应用中表单处理的重要性和实现步骤。表单处理包括创建表单…

数据结构(Java版)第六期:LinkedList与链表(一)

目录 一、链表 1.1. 链表的概念及结构 1.2. 链表的实现 专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 一、链表 1.1. 链表的概念及结构 链表是⼀种物理存储结构上⾮连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引⽤链接次序实现的。与火车…