深入剖析 MySQL 自增锁
在数据库实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《深入剖析 MySQL 自增锁》,聊聊MySQL、InnoDB,希望可以帮助到正在努力赚钱的你。
之前的文章把 InnoDB 中的所有的锁都介绍了一下,包括意向锁、记录锁...自增锁巴拉巴拉的。但是后面我自己回过头去看的时候发现,对自增锁的介绍居然才短短的一段。
其实自增锁(AUTO-INC Locks)这块还是有很多值得讨论的细节,例如在并发的场景下,InnoDB 是如何保证该值正确的进行自增的,本章就专门来简单讨论一下 InnoDB 中的自增锁。
什么是自增锁
之前我们提到过,自增锁是一种比较特殊的表级锁。并且在事务向包含了
AUTO_INCREMENT列的表中新增数据时就会去持有自增锁,假设事务 A 正在做这个操作,如果另一个事务 B 尝试执行
INSERT语句,事务 B 会被阻塞住,直到事务 A 释放自增锁。
这怎么说呢,说他对,但是他也不完全对。
行为与限制
其实上面说的那种阻塞情况只是自增锁行为的其中一种,可以理解为自增锁就是一个接口,其具体的实现有多种。具体的配置项为
innodb_autoinc_lock_mode,通过这个配置项我们可以改变自增锁中运行的一些细节。
并且,自增锁还有一个限制,那就是被设置为
AUTO_INCREMENT的列必须是索引,或者该列是索引的一部分(联合索引),不过这个限制对于大部分开发场景下并没有什么影响。
毕竟我们的基操不就是把 id 设置为AUTO_INCREMENT吗。
锁模式
其实在 InnoDB 中,把锁的行为叫做锁模式可能更加准确,那具体有哪些锁模式呢,如下:
- 传统模式(Traditional)
- 连续模式(Consecutive)
- 交叉模式(Interleaved)
分别对应配置项
innodb_autoinc_lock_mode的值0、1、2.
看到这就已经知道为啥上面说不准确了,因为三种模式下,InnoDB 对并发的处理是不一样的,而且具体选择哪种锁模式跟你当前使用的 MySQL 版本还有关系。
在 MySQL 8.0 之前,InnoDB 锁模式默认为连续模式,值为1,而在 MySQL 8.0 之后,默认模式变成了交叉模式。至于为啥会改变默认模式,后面会讲。
传统模式
传统模式(Traditional),说白了就是还没有锁模式这个概念时,InnoDB 的自增锁运行的模式。只是后面版本更新,InnoDB 引入了锁模式的概念,然后 InnoDB 给了这种以前默认的模式一个名字,叫——传统模式。
传统模式具体是咋工作的?

我们知道,当我们向包含了
AUTO_INCREMENT列的表中插入数据时,都会持有这么一个特殊的表锁——自增锁(AUTO-INC),并且当语句执行完之后就会释放。这样一来可以保证单个语句内生成的自增值是连续的。
这样一来,传统模式的弊端就自然暴露出来了,如果有多个事务并发的执行
INSERT操作,
AUTO-INC的存在会使得 MySQL 的性能略有下降,因为同时只能执行一条
INSERT语句。
连续模式
连续模式(Consecutive)是 MySQL 8.0 之前默认的模式,之所以提出这种模式,是因为传统模式存在影响性能的弊端,所以才有了连续模式。
在锁模式处于连续模式下时,如果
INSERT语句能够提前确定插入的数据量,则可以不用获取自增锁,举个例子,像
INSERT INTO这种简单的、能提前确认数量的新增语句,就不会使用自增锁,这个很好理解,在自增值上,我可以直接把这个
INSERT语句所需要的空间流出来,就可以继续执行下一个语句了。
但是如果
INSERT语句不能提前确认数据量,则还是会去获取自增锁。例如像
INSERT INTO ... SELECT ...这种语句,
INSERT的值来源于另一个
SELECT语句。
连续模式的图和交叉模式差不多
交叉模式
交叉模式(Interleaved)下,所有的
INSERT语句,包含
INSERT和
INSERT INTO ... SELECT,都不会使用
AUTO-INC自增锁,而是使用较为轻量的
mutex锁。这样一来,多条
INSERT语句可以并发的执行,这也是三种锁模式中扩展性最好的一种。

并发执行所带来的副作用就是单个
INSERT的自增值并不连续,因为
AUTO_INCREMENT的值分配会在多个
INSERT语句中来回交叉的执行。
优点很明确,缺点是在并发的情况下无法保证数据一致性,这个下面会讨论。
交叉模式缺陷
要了解缺陷是什么,还得先了解一下 MySQL 的 Binlog。Binlog 一般用于 MySQL 的数据复制,通俗一点就是用于主从同步。在 MySQL 中 Binlog 的格式有 3 种,分别是:
- Statement 基于语句,只记录对数据做了修改的SQL语句,能够有效的减少binlog的数据量,提高读取、基于binlog重放的性能
- Row 只记录被修改的行,所以Row记录的binlog日志量一般来说会比Statement格式要多。基于Row的binlog日志非常完整、清晰,记录了所有数据的变动,但是缺点是可能会非常多,例如一条
update
语句,有可能是所有的数据都有修改;再例如alter table
之类的,修改了某个字段,同样的每条记录都有改动。 - Mixed Statement和Row的结合,怎么个结合法呢。例如像
alter table
之类的对表结构的修改,采用Statement格式。其余的对数据的修改例如update
和delete
采用Row格式进行记录。
如果 MySQL 采用的格式为
Statement,那么 MySQL 的主从同步实际上同步的就是一条一条的 SQL 语句。如果此时我们采用了交叉模式,那么并发情况下
INSERT语句的执行顺序就无法得到保障。
可能你还没看出问题在哪儿,
INSERT同时交叉执行,并且
AUTO_INCREMENT交叉分配将会直接导致主从之间同行的数据主键 ID 不同。而这对主从同步来说是灾难性的。

换句话说,如果你的 DB 有主从同步,并且 Binlog 存储格式为 Statement,那么不要将 InnoDB 自增锁模式设置为交叉模式,会有问题。其实主从同步的过程远比上图中的复杂,之前我也写过详细的MySQL主从同步的文章,感兴趣可以先去看看。
而后来,MySQL 将日志存储格式从
Statement变成了
Row,这样一来,主从之间同步的就是真实的行数据了,而且
主键ID在同步到从库之前已经确定了,就对同步语句的顺序并不敏感,就规避了上面
Statement的问题。
基于 MySQL 默认 Binlog 格式从
Statement到
Row的变更,InnoDB 也将其自增锁的默认实现从连续模式,更换到了效率更高的交叉模式。
鱼和熊掌
但是如果你的 MySQL 版本仍然默认使用连续模式,但同时又想要提高性能,该怎么办呢?这个其实得做一些取舍。
如果你可以断定你的系统后续不会使用 Binlog,那么你可以选择将自增锁的锁模式从连续模式改为交叉模式,这样可以提高 MySQL 的并发。并且,没有了主从同步,
INSERT语句在从库乱序执行导致的
AUTO_INCREMENT值不匹配的问题也就自然不会遇到了。
总结
你可能会说,为啥要了解这么深?有啥用?
其实还真有,例如在业务中你有一个需要执行 几十秒 的脚本,脚本中不停的调用多次
INSERT,这时就问你这个问题,在这几十秒里,会阻塞其他的用户使用对应的功能吗?
如果你对自增锁有足够的了解,那么这个问题将会迎刃而解。
本篇文章已放到我的 Github github.com/sh-blog 中,欢迎 Star。微信搜索关注【SH的全栈笔记】,回复【队列】获取MQ学习资料,包含基础概念解析和RocketMQ详细的源码解析,持续更新中。
如果你觉得这篇文章对你有帮助,还麻烦点个赞,关个注,分个享,留个言。
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于数据库的相关知识,也可关注golang学习网公众号。
工具 | 使用 CLion 编译调试 MySQL 8.0
- 上一篇
- 工具 | 使用 CLion 编译调试 MySQL 8.0
- 下一篇
- Ubuntu搭建Mysql+Keepalived高可用(双主热备)
-
- 数据库 · MySQL | 23小时前 |
- MySQL数值函数大全及使用技巧
- 117浏览 收藏
-
- 数据库 · MySQL | 2天前 |
- 三种登录MySQL方法详解
- 411浏览 收藏
-
- 数据库 · MySQL | 3天前 |
- MySQL数据备份方法与工具推荐
- 420浏览 收藏
-
- 数据库 · MySQL | 3天前 |
- MySQL数据备份方法与工具推荐
- 264浏览 收藏
-
- 数据库 · MySQL | 4天前 |
- MySQL索引的作用是什么?
- 266浏览 收藏
-
- 数据库 · MySQL | 5天前 |
- MySQL排序原理与实战应用
- 392浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQLwhere条件查询技巧
- 333浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL常用数据类型有哪些?怎么选更合适?
- 234浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL常用命令大全管理员必学30条
- 448浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL高效批量插入数据方法大全
- 416浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL性能优化技巧大全
- 225浏览 收藏
-
- 数据库 · MySQL | 1星期前 |
- MySQL数据备份4种方法保障安全
- 145浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3162次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3375次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3403次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4506次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3784次使用
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- 搞一个自娱自乐的博客(二) 架构搭建
- 2023-02-16 244浏览
-
- B-Tree、B+Tree以及B-link Tree
- 2023-01-19 235浏览
-
- mysql面试题
- 2023-01-17 157浏览
-
- MySQL数据表简单查询
- 2023-01-10 101浏览

