当前位置: 首页 > article >正文

MySQL锁机制:从懵逼到入门,我花了三年

MySQL锁机制从懵逼到入门我花了三年写在前面这篇文章源于我被死锁折磨的那些日日夜夜。如果你也曾经对着SHOW ENGINE INNODB STATUS发呆或者被间隙锁搞得怀疑人生那这篇文章可能就是为你写的。一、故事的开始一个诡异的阻塞三年前我刚接手一个电商项目。某天凌晨两点报警群炸了“订单创建接口超时”。我睡眼惺忪地打开监控发现数据库有一堆Lock wait。再看慢查询日志有一条 SQL 格外刺眼SELECT*FROMordersWHEREorder_id12345FORUPDATE;“这不就是查个订单吗怎么还能把数据库卡死” 我当时是这么想的。后来才知道order_id 12345这条记录根本不存在。而在 Repeatable Read 隔离级别下这条 SQL 竟然锁住了整个间隙导致所有插入订单的请求都被阻塞。那一刻我意识到我对 MySQL 锁的理解基本为零。二、锁的粒度从粗到细表锁简单粗暴想象一下你家的卫生间。表锁就像是给整个卫生间上锁。你要上厕所必须把整个卫生间的门锁上。别人想洗手不行等着。想刷牙也得等着。MyISAM 引擎就是这么干的。它的优点是实现简单开销小。缺点嘛……并发性能惨不忍睹。-- 表级读锁LOCKTABLESmy_tableREAD;-- 表级写锁LOCKTABLESmy_tableWRITE;行锁精细管理行锁就像是给卫生间的每个设施单独上锁。马桶、洗手池、淋浴间各自独立。你可以用马桶别人可以同时洗手。InnoDB 引擎支持行锁。这是它成为 MySQL 默认引擎的重要原因之一。但有个坑行锁是锁在索引上的这句话我说了无数遍但很多人还是不信。来看个例子-- 假设 id 是主键SELECT*FROMusersWHEREname张三FORUPDATE;如果name字段没有索引InnoDB 会怎么做全表扫描然后锁住每一行这跟表锁有什么区别所以一定要加索引。这不是建议是铁律。三、锁的模式共享与排他共享锁S锁大家一起看共享锁就是读锁。你可以看我也可以看但谁都不能改。SELECT*FROMusersWHEREid1LOCKINSHAREMODE;-- MySQL 8.0SELECT*FROMusersWHEREid1FORSHARE;排他锁X锁这是我的排他锁就是写锁。我拿了这把锁别人既不能看某些情况下也不能改。UPDATEusersSETage25WHEREid1;-- 或者SELECT*FROMusersWHEREid1FORUPDATE;意向锁提前打招呼这个概念很多人不理解。意向锁是表级锁用来告诉别人“我准备对表里的某些行加锁了”。意向共享锁IS我打算给某些行加 S 锁。意向排他锁IX我打算给某些行加 X 锁。有什么用假设你想给整个表加排他锁LOCK TABLES ... WRITE你怎么知道表里有没有行被锁住了总不能一行行检查吧这时候意向锁就派上用场了。只要检查表上有没有 IS 或 IX 锁就知道有没有行被锁住。四、三种锁算法核心难点来了这部分是重头戏也是大多数人包括当年的我最容易混淆的地方。1. 记录锁Record Lock最简单就是锁住某一行。-- 假设 id3 存在SELECT*FROMusersWHEREid3FORUPDATE;这条 SQL 会对id3这一行加排他锁。2. 间隙锁Gap Lock这个就有点意思了。它不锁记录只锁间隙。假设表里有id 1, 3, 5, 7。你执行SELECT*FROMusersWHEREid4FORUPDATE;id4不存在对吧但在 Repeatable Read 隔离级别下InnoDB 会加一个间隙锁锁住(3, 5)这个区间。为什么要这么做防止幻读。如果别人在你查询的间隙里插入了一条id4的记录你再次查询时就会看到这条凭空出现的数据这就是幻读。3. 临键锁Next-Key Lock这个名字听起来很玄乎其实就是记录锁 间隙锁的组合。InnoDB 在 Repeatable Read 级别下默认使用临键锁。它锁住的是(prev, current]这个区间左开右闭。举个例子表里有id 2, 5, 9。你执行SELECT*FROMusersWHEREid5ANDid9FORUPDATE;InnoDB 会怎么加锁对id5加临键锁锁住(2, 5]对id9加临键锁锁住(5, 9]注意不会锁住(9, ∞)因为你的查询条件是 9插入id10不会影响你的查询结果。一个重要的优化很多人不知道InnoDB 有个聪明的优化如果是唯一索引的等值查询且记录存在临键锁会退化成记录锁。-- id 是主键唯一索引SELECT*FROMusersWHEREid5FORUPDATE;-- id5 存在这条 SQL 只会对id5加记录锁不会加间隙锁。为什么因为id是唯一的不可能有另一条id5的记录插入。既然不会有幻读为什么要锁间隙这个优化极大地提高了并发性能。五、隔离级别锁的行为大不同MySQL 有四种隔离级别但常用的只有两种Read Committed (RC)和Repeatable Read (RR)。RR默认安全但保守RR 是 MySQL 的默认隔离级别。它的特点是使用临键锁防止幻读范围查询会锁住间隙并发性能相对较低RC激进但高效RC 隔离级别下不加间隙锁这是关键只锁住实际存在的记录并发性能更高这意味着什么在 RC 级别下你执行SELECT*FROMusersWHEREid4FORUPDATE;-- id4 不存在不会加任何锁因为记录不存在RC 级别不会加间隙锁。再比如SELECT*FROMusersWHEREid5ANDid9FORUPDATE;只会对id5和id9加记录锁不会锁住间隙。别人可以自由插入id6, 7, 8。那幻读怎么办RC 级别允许幻读。这是用一致性换取性能的权衡。我该选哪个金融、支付类系统用 RR数据一致性更重要高并发互联网应用考虑 RC性能更重要当然要能接受幻读我参与过的项目90% 都改成了 RC 级别。原因很简单间隙锁导致的锁等待真的太常见了。六、MVCC锁的好兄弟很多人以为防止脏读、不可重复读、幻读全靠锁。这是错的。InnoDB 有个神器叫MVCC多版本并发控制。它的作用是普通 SELECT快照读不加锁通过 MVCC 读取历史版本防止脏读只能看到已提交的数据防止不可重复读RR 级别整个事务看到同一个快照关键区别-- 快照读不加锁用 MVCCSELECT*FROMusersWHEREid1;-- 当前读加锁读最新版本SELECT*FROMusersWHEREid1FORUPDATE;UPDATEusersSETage25WHEREid1;DELETEFROMusersWHEREid1;所以防止幻读的机制有两个快照读靠 MVCCRR 级别下整个事务看到同一个快照自然不会有幻读当前读靠间隙锁/临键锁防止别人插入新数据七、实战如何排查锁问题理论说了这么多来点实际的。1. 查看当前锁-- MySQL 8.0SELECT*FROMperformance_schema.data_locks;-- 查看锁等待SELECT*FROMperformance_schema.data_lock_waits;2. 查看死锁信息SHOWENGINEINNODBSTATUS;在输出结果里找LATEST DETECTED DEADLOCK部分。这里会详细告诉你哪个事务持有什么锁哪个事务在等待什么锁死锁是怎么形成的3. 一个真实的死锁案例事务 ABEGIN;UPDATEusersSETage25WHEREid1;UPDATEusersSETage26WHEREid2;事务 BBEGIN;UPDATEusersSETage27WHEREid2;UPDATEusersSETage28WHEREid1;看到了吗事务 A 锁了id1想锁id2事务 B 锁了id2想锁id1。典型的死锁。解决方案统一访问顺序。所有事务都先访问id1再访问id2。4. 间隙锁导致的阻塞这个更隐蔽。事务 ABEGIN;SELECT*FROMusersWHEREid100FORUPDATE;-- id100 不存在事务 BINSERTINTOusers(id,name)VALUES(100,张三);-- 阻塞为什么因为事务 A 在 RR 级别下对不存在的id100加了间隙锁。事务 B 的插入操作被阻塞。解决方案改用 RC 隔离级别确保查询的记录存在用INSERT ... ON DUPLICATE KEY UPDATE代替SELECT INSERT/UPDATE八、避坑指南我踩过的雷坑 1忘记加索引-- name 字段没有索引SELECT*FROMusersWHEREname张三FORUPDATE;后果全表锁。所有对users表的写操作都会被阻塞。检查方法用EXPLAIN看 SQL 是否走索引。坑 2范围查询锁住大片间隙SELECT*FROMordersWHEREcreated_at2024-01-01FORUPDATE;后果锁住从2024-01-01到正无穷的所有间隙。新订单无法插入。解决方案改用 RC 隔离级别缩小查询范围比如只查某一天的订单避免对范围查询加锁坑 3大事务长时间持有锁BEGIN;-- 处理 10000 条订单UPDATEordersSETstatus1WHEREidIN(...);-- 发送 10000 封邮件-- 调用外部 API-- ... 过了 30 秒COMMIT;后果锁被持有 30 秒其他事务全部阻塞。解决方案大事务拆成小事务批量处理每 100 条提交一次把耗时操作发邮件、调 API放到事务外坑 4RR 级别下批量插入不存在的 ID-- 批量检查订单是否存在SELECTidFROMordersWHEREidIN(1001,1002,1003,...)FORUPDATE;-- 然后插入不存在的订单如果这些 ID 都不存在在 RR 级别下会锁住大片间隙导致并发插入性能极差。解决方案改用 RC用INSERT ... ON DUPLICATE KEY UPDATE先查已存在的 ID只处理不存在的九、最佳实践我现在的做法经过这些年的踩坑我总结了一套自己的实践1. 隔离级别默认 RC除非有强一致性要求否则一律用 RC。间隙锁导致的性能问题真的太常见了。2. 索引必须加所有WHERE、JOIN、ORDER BY的字段都要考虑加索引。用EXPLAIN验证。3. 事务越小越好只包含必要的 SQL耗时操作放到事务外批量操作分批提交4. 锁能不用就不用优先用乐观锁version字段避免SELECT ... FOR UPDATE除非真的需要如果必须用确保走唯一索引5. 监控必须做监控锁等待时间监控死锁次数定期分析慢查询日志十、总结MySQL 的锁机制说复杂也复杂说简单也简单。核心就几点行锁是锁在索引上的—— 没索引 表锁RR 级别有间隙锁RC 级别没有—— 这是性能差异的关键临键锁 记录锁 间隙锁—— RR 级别的默认策略MVCC 负责快照读锁负责当前读—— 两者配合实现隔离唯一索引等值查询会优化—— 临键锁退化成记录锁最后送大家一句话锁是用来保护数据的不是用来折磨开发者的。理解它才能用好它。希望这篇文章能帮你少走点弯路。如果还有疑问欢迎留言讨论。毕竟我也是从懵逼过来的。参考资源MySQL 官方文档InnoDB Locking《高性能 MySQL》第 7 章源码storage/innobase/lock/lock0lock.cc实验环境MySQL 8.0.32隔离级别Repeatable Read除非特别说明引擎InnoDB如果你觉得这篇文章有帮助欢迎转发给更多被锁折磨的朋友。毕竟独惨惨不如众惨惨开玩笑的是共同进步。

相关文章:

MySQL锁机制:从懵逼到入门,我花了三年

MySQL锁机制:从懵逼到入门,我花了三年写在前面:这篇文章源于我被死锁折磨的那些日日夜夜。如果你也曾经对着 SHOW ENGINE INNODB STATUS 发呆,或者被间隙锁搞得怀疑人生,那这篇文章可能就是为你写的。一、故事的开始&a…...

小程序制作平台有哪些?SaaS模板类平台评测

在数字化转型加速的当下,小程序已成为商家触达用户、提升营收的核心载体,而SaaS模式凭借零代码、低成本、快速上线的优势,成为多数商家搭建小程序的首选。目前市场上SaaS小程序制作平台众多,其中码云数智、有赞、微盟凭借各自的定…...

人工智能之数字生命--“骨架真相”

现在这套系统里,安全值 和 服务值 的根需求负责给出总方向,真根任务不会真正“完成”,它们会反复根据当前状态去分解出下一轮阶段任务。真正会完成的,是这些阶段任务下面的叶子子任务。 下面我用你现在代码里的机制,推…...

Ozon卖家醒醒吧!别再“手动搬砖”了,你的对手已经在用AI“开挂”了

做跨境电商十几年,我从最早的eBay、速卖通,到后来的亚马逊,再到现在的Ozon,一路摸爬滚打过来。说实话,见过太多卖家起高楼、宴宾客、楼塌了的戏码。特别是最近两年,Ozon火了,俄罗斯市场的大门越…...

RedisSearch 和 Elasticsearch 的 HNSW向量索引对比

RedisSearch 和 Elasticsearch 都支持 HNSW(Hierarchical Navigable Small World)向量索引,但它们在存储方式、查询流程、扩展能力、性能侧重点上差异很大。很多人在做向量检索架构选型时都会对比这两者。 下面从 架构 → 存储 → 检索 → 性…...

专注AI优化的服务商

随着人工智能技术向各行业深度渗透,企业在AI应用过程中常面临模型效率低、部署成本高、场景适配难等核心痛点。专注AI优化的服务商成为破解这些问题的关键力量,而超智引擎人工智能科技凭借其专业技术能力与深度行业经验,为企业提供高效的AI优…...

C# .NET 周刊|2026年2月4期

国内文章 Zenith.NET v0.0.6 发布 — API 大幅精简,为 Metal 后端铺路 https://www.cnblogs.com/xymfblogs/p/19620088 Zenith.NET v0.0.6 正式发布,核心主题是精简。大规模重构资源绑定模型、着色器阶段和光线追踪方案。资源集合重命名为 ResourceTa…...

一个寒假过去了 把虚拟机密码忘了怎么办

此时需要重启或开启虚拟机出现一下界面快速点进虚拟机按上下选择第二个选项按e进入以下界面 并在quiet 单词后输入rd.break 按下ctrlx进入以下界面输入mount -o remount,rw /stsrootchroot /sysrootpasswd新密码再次确认新密码touch /.autorelabelexitexit回车后系统会重启...

【流程思维】九、行动:实验和科学方法打造持续改进的组织

导读:以“科学方法无惧失败”推动流程改善,主张用“5W1H”审视惯性动作,遵循观察—假设—实验—验证循环,并以心理安全和复盘机制化解对失败的恐惧,形成小步快跑的持续进化文化。 目录 1. 停止磕绊,开启思…...

杨立昆的“世界模型”获10亿美元背书:AI要从“语言”走向“现实”

杨立昆的“世界模型”获10亿美元背书:AI要从“语言”走向“现实”2026年3月,图灵奖得主杨立昆(Yann LeCun)的新公司AMI Labs宣布完成10.3亿美元巨额融资,这笔资金将用于打造能真正理解物理现实的“世界模型”&#xff…...

互联网大厂Java面试三轮详解:核心技术栈与业务场景代码实践

互联网大厂Java面试三轮详解 本文旨在帮助初学者系统学习并应对互联网大厂的Java求职面试。内容体系化,模拟三轮真实面试流程,涵盖核心技术栈,结合实际业务场景和代码演示。每部分均附详细技术解析,助力面试准备。第一轮&#xff…...

Ubuntu 服务器通过 Samba 映射至 Windows 本地:高性能配置全攻略

这里写自定义目录标题Ubuntu 服务器通过 Samba 映射至 Windows 本地:高性能配置全攻略一、 为什么选择 Samba?二、 环境准备与基础安装三、 核心配置:性能与权限的深度优化关键参数解析:四、 用户授权与服务激活五、 Windows 映射…...

世界读书日|与AI共舞,在阅读中寻找你的不可替代性

世界读书日|与AI共舞,在阅读中寻找你的不可替代性当AI能快速生成文案、拆解书籍、解答疑惑,甚至模拟思维输出内容,不少人陷入迷茫:AI时代,我们还需要静下心来阅读吗?答案毋庸置疑。阅读从来不是…...

VMware 17安装 RHEL 8 并且使用xshell ssh连接指南

一、准备工作Vmware安装包,RHEL 8镜像文件, xshell 客户端二、打开Vmware新建虚拟机,点击稍后选择iso的选项之后选择Linux并且选择“Red Hat Enterprise Linux 8 64位”之后根据自己电脑配置设置好虚拟机的参数网络适配器选项必须选择NAT桥接…...

TR-069 交互流程规范更新总结

TR-069 交互流程规范更新总结 更新时间 2026-03-15 更新版本 v3.0 - 基于 TR-069 Amendment 6 官方文档的全面调整 主要更新内容 一、协议栈架构完善(Section 2) 1. 新增官方协议栈结构 ┌─────────────────────────────┐ │ CPE/ACS …...

前端:第四章-样式系统搭建

第四章:样式系统搭建 🎯 本章目标:安装配置 Tailwind CSS,定制主题色彩,实现深色模式支持。 4.1 安装 Tailwind CSS 4.1.1 什么是 Tailwind CSS? Tailwind CSS 是一个原子化 CSS 框架,特点如下: 特性 说明 原子化 预定义的工具类,无需写 CSS 可定制 完全可配置的设…...

Qt+C++ 控制软件架构实例

我给你讲一个接近真实工业项目规模(10万~20万行代码)的 QtC 控制软件架构实例。 我会按照 真实工程师的思考过程来讲: 1️⃣ 项目背景 2️⃣ 第一版代码(很混乱) 3️⃣ 第一次架构升级 4️⃣ 第二次架构升级 5️⃣ 第三…...

大模型 RAG 中 RRF(Reciprocal Rank Fusion倒数排序融合)是什么

大模型 RAG 中 RRF(Reciprocal Rank Fusion倒数排序融合)是什么 Reciprocal Rank Fusion (RRF) 是一种将多个搜索结果列表(比如 ES 的全文检索列表和向量搜索列表)合并成一个统一排名列表的算法。它的核心思想非常朴素且强大&…...

论文排版之添加图片、表格、公式的题注

添加图片、表格、公式的题注 不想手动输入域代码教程在 WPS 上使用教学视频 题注能为图片、表格、公式添加智能编号,避免手动修改的麻烦。 1. 插入题注 a. 选中对象,在【引用】选项卡点击【插入题注】。(也可以不选中对象,直接在…...

无需服务器!Windows 部署 OpenClaw,打造私人 AI助手

欢迎来到我的博客,代码的世界里,每一行都是一个故事🎏:你只管努力,剩下的交给时间 🏠 :小破站 无需服务器!Windows 部署 OpenClaw,打造私人 AI助手前言1 什么是OpenClaw&…...

kubernetes知识点汇总13-18

13. 系统默认创建了哪几个namespace?答:default:用户创建资源对象时的默认命名空间。kube-node-lease:包含用于与各个节点关联的lease(租约)对象,lease保证kubelet可 以向api-server发送心跳&am…...

C语言指针概念详解:数组指针与二级指针的本质区别

前言 最近考研复试在复习C语言,突然看到以前初学时没有深究的一个知识点:数组指针与指针数组(int (*p)[5] vs int *p[5]) 之前一直以为这它们虽然一个本质是指针,一个本质是数组,但是二者同为二级指针&am…...

利用qwen 3.5-9b模型识别几何图像并转换成latex tikz代码

一开始用的是0.8b,没有识别成功,重复输出\\draw [blue] (1,-1) -- (0,0);\n\\draw [blue] (0,0) -- (1,0);, 被我终止了。 再用大一点的9b试一下,以前编写python程序就遇到0.8b错误,而9b正确的情况。 先下载9b的mmproj文件&…...

“十五五”规划:新建若干所新型研究型大学

以下内容转载自微信公众号“青塔”,仅作分享 原文链接:https://mp.weixin.qq.com/s/fy9WLPuZ3T_u_D1ywoK7rQ 近日,新华社受权全文播发《中华人民共和国国民经济和社会发展第十五个五年规划纲要》与李强总理代表国务院在十四届全国人大四次会…...

AIA | 西工大马启悦,高传强等:物理指导的激波抖振抑制翼型优化设计研究

物理指导的激波抖振抑制翼型优化设计研究 Physics-guided airfoil optimization design for shock buffet suppression 马启悦,高传强*,邬晓敬,张伟伟 引用格式: Ma Q, Gao C, Wu X, et al. Physics-guided airfoil optimizatio…...

【杂谈】-人工智能蓬勃演进背后的隐性支撑体系

人工智能蓬勃演进背后的隐性支撑体系 文章目录人工智能蓬勃演进背后的隐性支撑体系1、人工智能扩张正改写资源需求格局2、降低对社区的影响,已成为企业发展的紧迫使命3、从公开承诺迈向基础设施层面的实质性变革4、立足资源约束,开展基础设施创新设计人工…...

【MicroPython编程-ESP32篇:设备驱动】-8x8LED点阵驱动(基于Max7219+SPI)

8x8LED点阵驱动(基于Max7219+SPI) 文章目录 8x8LED点阵驱动(基于Max7219+SPI) 1、Max7219 LED驱动器介绍 2、软件准备 3、硬件准备 4、代码实现 4.1 MAX7219传感器驱动 4.2 主程序 1、Max7219 LED驱动器介绍 MAX7219/MAX7221是一款紧凑型串行输入/输出共阴极显示驱动器,可将微…...

实战演练:从零构建基于线性表的图书管理系统

1. 为什么选择线性表实现图书管理系统 刚接触数据结构时,很多人会疑惑:为什么图书管理系统要用线性表实现?这个问题我也思考了很久。直到去年帮学校图书馆升级系统时,我才真正理解线性表的优势。想象一下图书馆的书架,…...

Kali 离线环境部署 ipmitool 实战指南

1. 为什么要在Kali离线环境折腾ipmitool? 如果你和我一样,经常需要带着Kali Linux笔记本钻进机房、数据中心,或者在一些网络隔离的敏感环境里做安全评估或运维工作,那你肯定对“离线”这两个字又爱又恨。爱的是,离线环…...

ECharts高级技巧:动态控制饼图hover效果,让隐藏数据真正‘消失‘

ECharts高级技巧:动态控制饼图hover效果,让隐藏数据真正"消失" 在数据可视化领域,ECharts作为一款强大的JavaScript图表库,其灵活性和定制化能力一直备受开发者青睐。特别是在处理复杂交互场景时,ECharts提供…...