一文详解MySQL不同隔离级别都使用什么锁
本篇文章给大家分享《一文详解MySQL不同隔离级别都使用什么锁》,覆盖了数据库的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。
在上篇文章,我们聊了「MySQL 啥时候会用表锁,啥时候用行锁」这个问题。在文章中,我们还留了一个问题,即:如果查询或更新时的数据特别多,是否从行锁会升级为表锁?
此外,还有朋友留言说到:不同的隔离级别可能会用不同的锁,可以结合隔离级别来聊聊。其实上面虽然是两个问题,但如果你把不同隔离级别下的加锁问题搞清楚了,那么第一个问题自然也清楚了。
今天,就让我带着大家来聊聊不同隔离级别下,都会使用什么锁!
文章思维导图
说透 MySQL 锁机制
在深入探讨不同隔离级别的锁内容之前,我们需要先回顾一下关于 MySQL 锁的本质以及一些基础内容,这样有利于我们后续的理解。
对于 MySQL 来说,如果只支持串行访问的话,那么其效率会非常低。因此,为了提高数据库的运行效率,MySQL 需要支持并发访问。
而在并发访问的情况下,会发生各种各样的问题,例如:脏读、不可重复读、幻读等问题。为了解决这些问题,就出现了事务隔离级别。
本质上,事务隔离级别就是为了解决并发访问下的数据一致性问题的。不同的事务隔离级别,解决了不同程度的数据一致性。
而我们所说的全局锁、表锁、行级锁等等,其实都是事务隔离级别的具体实现。而 MVCC、意向锁,则是一些局部的性能优化。
上面这段话,基本上就是对 MySQL 锁机制很透彻的理解。当我们懂了这些概念之间的关系之后,我们才能更加清晰地理解知识点。
事务隔离级别
相信大家都知道,MySQL 的事务隔离级别有如下 4 个,分别是:
- 读未提交
- 读已提交(READ COMMITTED)
- 可重复读(REPEATABLE READ)
- 串行化
读未提交,可以读取到其他事务还没提交的数据。 在这个隔离级别下,由于可以读取到未提交的值,因此会产生「脏读」问题。举个例子:A 事务更新了 price 为 30,但还未提交。此时 B 事务读取到了 price 为 30,但后续 A 事务回滚了,那么 B 事务读取到的 price 就是错的(脏的)。
读已提交,只能读到其他事务已经提交的数据。 这个隔离级别解决了脏读的问题,不会读到未提交的值,但是却会产生「不可重复读」问题。「不可重复读」指的是在同一个事务范围内,前后两次读取到的数据不一样。举个例子:A 事务第 1 次读取了 price 为 10。
随后 B 事务将 price 更新为 20,接着 A 事务再次读取 price 为 30。A 事务前后两次读取到的数据是不一样的,这就是不可重复读。
思考题:MySQL 读已提交可以解决脏读问题,那它具体是如何解决的?
可重复读,指的是同一事务范围内读取到的数据是一致的。 这个隔离级别解决了「不可重复读」的问题,只要是在同一事务范围内,那么读取到的数据就是一样的。对于 MySQL Innodb 来说,其实通过 MVCC 来实现的。但「可重复读」隔离级别会产生幻读问题,即对于某个范围的数据读取,前后两次可能读取到不同的结果。
举个例子:数据库中有 price 为 1、3、5 三个商品,此时 A 事务查询 price
可以看到「幻读」与「不可重复读」是有些类似的,只是「不可重复读」更多指的是某一条记录,而「幻读」指的则是某个范围数据。对于 MySQL Innodb 来说,其通过行级锁级别的 Gap Lock 解决了幻读的问题。
串行化,指的是所有事务串行执行。 这个就最简单了,不用去竞争,一个个去执行,但是效率也是最低的。
MySQL 锁类型
在 MySQL 中有全局锁、表级锁、行级锁三种类型,其中比较关键的是表级锁盒行级锁。
对于表级锁而言,其又分为表锁、元数据锁、意向锁三种。对于元数据锁而言,基本上都是数据库自行操作,我们无须关心。在 Innodb 存储存储引擎中,表锁也用得比较少。
对于行级锁而言,其又记录锁、间隙锁、Next-Key 锁。记录锁就是某个索引记录的锁,间隙锁就是两个索引记录之间的空隙锁,Next-Key 则是前面两者的结合。
在 Innodb 存储引擎中,我们可以通过下面的命令来查询锁的情况。
// 开启锁的日志 set global innodb_status_output_locks=on; // 查看innodb引擎的信息(包含锁的信息) show engine innodb status\G;
查询结果一般如下图所示:
上面几种不同类型的锁,其各自的关键字为:
- 表级的意向排它锁(IX):lock mode IX。
- 表级的插入意向锁(LOCK_INSERT_INTENTION): lock_mode X locks gap before rec insert intention
- 行级的记录锁(LOCK_REC_NOT_GAP): lock_mode X locks rec but not gap
- 行级的间隙锁(LOCK_GAP): lock_mode X locks gap before rec
- 行级的 Next-key 锁(LOCK_ORNIDARY): lock_mode X
通过上面的命令,我们就可以知道不同的事务隔离级别使用了哪些锁了。
接下来,我们一个个来看看:不同事务隔离级别,都使用了哪些锁来实现。
读未提交
首先,我们创建一个 price_test 表并插入一些测试数据。
// 创建 price_test 表 CREATE TABLE `test`.`price_test` ( `id` BIGINT(64) NOT NULL AUTO_INCREMENT, `name` varchar(32) not null, `price` INTEGER(4) NULL, PRIMARY KEY (`id`)); // 插入测试数据 INSERT INTO price_test(name,price) values('apple', 10);
接着,我们打开两个命令行窗口,并且都修改事务隔离级别为「读未提交」。
// 设置隔离级别 SET session TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; // 查看隔离级别 select @@transaction_isolation;
接着,事务 A 执行如下命令,查询出 id 为 1 记录的 price 值。
// 执行命令 beign; select * from price_test where id = 1; // 执行结果 +----+-------+-------+ | id | name | price | +----+-------+-------+ | 1 | apple | 10 | +----+-------+-------+ 1 row in set (0.00 sec)
接着,事务 B 执行如下命令,修改 price 为 20。
begin; update price_test set price = 20 where id = 1;
接着,事务 A 再次读取 id 为 1 记录的 price 值。
select * from price_test where id = 1;
从下图可以看到,事务 A 读取到了事务 B 未提交的数据,这其实就是脏读了。
从这个例子,我们可以得出一些结论:在「读未提交」事务隔离级别下,读写是可以同时进行的,不会阻塞。
看到这里,我突然想到了一个问题:那么写写是否会阻塞阻塞呢?
接下来,我们继续做一个测试:事务 A 和 事务 B 同时对 id 为 1 的记录进行更新,看看是否能够更新成功。
如上图所示,我先用如下命令在事务 A(上边的窗口)执行,将 price 修改为 15。
begin; update price_test set price = 15 where id = 1;
结果执行成功了,但此时事务 A 还未提交。
接着,我先用如下命令在事务 B(下边的窗口)执行,将 price 修改为 20。
从图中可以看到,事务 B 阻塞卡住了。
从这个例子,我们可以得出结论:在「读未提交」事务隔离级别下,写写不可以同时进行的,会阻塞。
此时,我们通过查看锁信息可以看到,其是加上一个行级别的记录锁,如下图所示。
当我使用 rollback 命令回滚事务 A 之后,事务 B 立刻就执行了,并且事务 A 还读取到了事务 B 设置的值,如下图所示。
有些小伙伴会说:如果指定了非索引的列作为查询条件,是否会触发间隙锁呢?
接下来我们测试一下。
我们往 price_test 表再插入一条数据,此时数据库中的数据如下所示。
接着,我们在事务 A 执行如下命令,查询 price > 15 的记录。
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from price_test where price > 15 for update; +----+--------+-------+ | id | name | price | +----+--------+-------+ | 2 | orange | 30 | +----+--------+-------+ 1 row in set (0.00 sec)
接着,我们在事务 B 执行如下命令,查询 price > 5 的记录。
begin; select * from price_test where price > 5 for update;
从如下结果可以看到,事务 B 阻塞住了。
此时我们在事务 A 查看锁的情况,如下图所示。
从上图可以看出,MySQL 只是加上了一个记录锁,并没有加间隙锁。
最后我们总结一下:在「读未提交」隔离级别下,读写操作可以同时进行,但写写操作无法同时进行。与此同时,该隔离级别下只会使用行级别的记录锁,并不会用间隙锁。
读已提交
在「读已提交」隔离级别下,我们按之前的方式进行测试。
首先,我们设置一下隔离级别为「读已提交」。
// 设置隔离级别 SET session TRANSACTION ISOLATION LEVEL READ COMMITTED; // 查看隔离级别 select @@transaction_isolation;
接着,我们测试同时对 id 为 1 的数据进行更新,看看会发生什么。
事务 A 执行如下命令:
begin; update price_test set price = 15 where id = 1;
事务 B 执行如下命令
begin; update price_test set price = 20 where id = 1;
事务 B 阻塞了。查看下锁信息,如下图所示。
可以看到,其锁是一个行级别的记录锁,结果和「读未提交」的是一样的。
接下来,我们继续看看范围的查询是否会触发间隙锁。
事务 A 执行:
begin; select * from price_test where price > 5 for update;
事务 B 执行:
begin; select * from price_test where price > 15 for update;
事务 B 会阻塞,查看锁信息如下图所示。
可以看到,还是只有一个行级别的记录锁,并没有间隙锁。
看到这里,你会发现「读已提交」和「读未提交」非常相似。那么它们具体有啥区别呢?
其实他们的最大区别,就是「读已提交」解决了脏读的问题。
可重复读
在「读已提交」隔离级别下,我们按之前的方式进行测试。
首先,我们设置一下隔离级别为「读已提交」。
// 设置隔离级别 SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ; // 查看隔离级别 select @@transaction_isolation;
接着,我们测试同时对 id 为 1 的数据进行更新,看看会发生什么。
事务 A 执行如下命令:
begin; update price_test set price = 15 where id = 1;
事务 B 执行如下命令
begin; update price_test set price = 20 where id = 1;
事务 B 阻塞了。查看下锁信息,毫无疑问,其实这里还是只会有间隙锁,因为指定了索引。
接下来,我们继续看看范围的查询是否会触发间隙锁。
事务 A 执行:
begin; select * from price_test where price > 5 for update;
事务 B 执行:
begin; select * from price_test where price > 15 for update;
事务 B 会阻塞,查看锁信息如下图所示。
可以看到,在这里就变成了 Next-Key 锁,就是记录锁和间隙锁结合体。
总结一下:在「可重复读」隔离级别下,使用了记录锁、间隙锁、Next-Key 锁三种类型的锁。
值得一提的是,我们前面说过:可重复读存在幻读的问题,但实际上在 MySQL 中,因为其使用了间隙锁,所以在「可重复读」隔离级别下,其实不存在幻读问题。因此,MySQL 将「可重复读」作为了其默认的隔离级别。
总结
看到这里,我想我们可以对文章开头提出的问题做个解答了:MySQL 不同隔离级别,都使用了什么样的锁?
对于任何隔离级别,表级别的表锁、元数据锁、意向锁都是会使用的,但对于行级别的锁则会有些许差别。
在「读未提交」和「读已提交」隔离级别下,都只会使用记录锁,不会用间隙锁,当然也不会有 Next-Key 锁了。
而对于「可重复读」隔离级别来说,会使用记录锁、间隙锁和 Next-Key 锁。
终于介绍完啦!小伙伴们,这篇关于《一文详解MySQL不同隔离级别都使用什么锁》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布数据库相关知识,快来关注吧!

- 上一篇
- Mysql数据库报错2003 Can't connect to MySQL server on 'localhost' (10061)解决

- 下一篇
- MySQL使用表锁和行锁的场景详解
-
- 欣慰的雪糕
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢作者大大分享技术贴!
- 2023-01-27 13:23:04
-
- 复杂的项链
- 好细啊,码起来,感谢师傅的这篇文章内容,我会继续支持!
- 2023-01-26 08:20:32
-
- 务实的泥猴桃
- 这篇技术文章太及时了,太全面了,受益颇多,码起来,关注师傅了!希望师傅能多写数据库相关的文章。
- 2023-01-25 23:28:00
-
- 兴奋的小蘑菇
- 太细致了,码住,感谢作者大大的这篇博文,我会继续支持!
- 2023-01-25 04:59:47
-
- 受伤的猎豹
- 这篇文章出现的刚刚好,up主加油!
- 2023-01-20 22:48:17
-
- 忧郁的灯泡
- 这篇技术贴出现的刚刚好,很详细,真优秀,已收藏,关注楼主了!希望楼主能多写数据库相关的文章。
- 2023-01-05 20:42:28
-
- 受伤的跳跳糖
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢楼主分享文章内容!
- 2023-01-01 06:11:04
-
- 数据库 · MySQL | 1天前 |
- MySQL设置中文界面,超简单教程来了!
- 332浏览 收藏
-
- 数据库 · MySQL | 1天前 | mysql 索引提示
- MySQL进阶必看!FORCE/USE/IGNOREINDEX用法大揭秘
- 182浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- 手把手教你写MySQL存储过程,小白也能轻松上手
- 163浏览 收藏
-
- 数据库 · MySQL | 1天前 | mysql group by
- MySQL分组查询优化:GROUPBY原理+索引优化超全解析
- 324浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL设置中文语言,轻松拥有中文界面
- 211浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL建库语句从入门到精通:创建数据库+设置字符集&排序规则(附实例)
- 176浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- 从零开始学MySQL数据库操作,小白轻松变大神!
- 496浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL插入日期到时间字段,轻松搞定日期格式
- 484浏览 收藏
-
- 数据库 · MySQL | 1天前 | mysql 数据压缩
- MySQL怎么实现高效压缩存储?表压缩+列式存储详细解读
- 272浏览 收藏
-
- 数据库 · MySQL | 1天前 | mysql JOIN优化
- MySQL优化JOIN操作:七大技巧教你提升关联查询速度
- 106浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL出现中文乱码?超详细解决方案一次性搞定
- 211浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL主从复制这样配!搞懂这些参数,replication稳了~
- 131浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 茅茅虫AIGC检测
- 茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
- 18次使用
-
- 赛林匹克平台(Challympics)
- 探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
- 50次使用
-
- 笔格AIPPT
- SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
- 57次使用
-
- 稿定PPT
- 告别PPT制作难题!稿定PPT提供海量模板、AI智能生成、在线协作,助您轻松制作专业演示文稿。职场办公、教育学习、企业服务全覆盖,降本增效,释放创意!
- 53次使用
-
- Suno苏诺中文版
- 探索Suno苏诺中文版,一款颠覆传统音乐创作的AI平台。无需专业技能,轻松创作个性化音乐。智能词曲生成、风格迁移、海量音效,释放您的音乐灵感!
- 57次使用
-
- go 分布式锁简单实现实例详解
- 2022-12-28 130浏览
-
- Redis实现事物以及锁的方法
- 2022-12-31 252浏览
-
- Redis锁被别人释放怎么办
- 2023-01-14 300浏览
-
- MySQL 中的 insERT 是怎么加锁的?
- 2023-01-08 350浏览
-
- 解析golang中的并发安全和锁问题
- 2023-02-24 178浏览