MySQL串行化隔离级别(间隙锁实现)


Posted in MySQL onJune 16, 2022

串行化隔离级别怎么解决幻读问题?
先说下幻读的含义,幻读就是在事务中按照同样的条件前后两次查询的结果数据量不同。

MySQL串行化隔离级别(间隙锁实现)

解决串行化的幻读问题用间隙锁(gap lock),间隙锁是给不存在的记录加锁,要正确理解间隙,知道间隙的范围。条件无非就是两类:范围查询和等值查询。再说下范围查询和等值查询都是怎么加间隙锁的,分别从主键索引和辅助索引两个场景来说。

一、间隙锁的概念

MySQL串行化隔离级别(间隙锁实现)

我们把事务2 select的指定的条件分为2类:范围查询、等值查询

record lock(记录锁,就是行锁)
gap lock(间隙锁)
next-key lock:record lock 和 gap lock

二、测试间隙锁范围加锁

设置事务为手动提交,隔离级别设置成串行化

MySQL串行化隔离级别(间隙锁实现)

查看表结构,id、age和name都有索引

MySQL串行化隔离级别(间隙锁实现)

场景1:用不可重复的主键id测试间隙锁

做范围查询

MySQL串行化隔离级别(间隙锁实现)

事务2的select操作只给三行数据加了排它锁,为什么插入id=24的数据也不行?

这是因为在串行化隔离级别中,不仅仅是获取了满足条件的这3行的行锁,而且把表数据后边空洞的地方也上了间隙锁。

MySQL串行化隔离级别(间隙锁实现)

图中红色线的地方都上了间隙锁,上锁范围(左开右闭)为:( 11 , 12 ] ∪ ( 12 , 22 ] ∪ ( 22 , 23 ] ∪ ( 23 , + ∞ ]

12,22,23是三个行记录,因为过滤条件是用id带有索引的,所以select获取了12,22,23的共享行锁(record-lock), 还把间隙加了间隙锁,其实就是给间隙加上共享锁或者排他锁,将间隙锁和行锁统称next-key lock(record-lock和gap-lock),也就是说where id>11加了next-key lock。正是因为给空洞也加锁了,所以事务1再想获取间隙的排它锁是不可以的,因为共享锁和排它锁是不能共存的。

由于事务2是select,所以是给间隙加上了共享锁,如果事务1做select id>11还是可以的,不能update、insert、delete id>11的数据。

场景2:用可重复的age(有索引)测试间隙锁

测试辅助索引树上,间隙锁的范围

我们先查看表结构、表数据,然后回滚。

MySQL串行化隔离级别(间隙锁实现)

根据表的内容建简单的辅助索引

MySQL串行化隔离级别(间隙锁实现)

开启事务进行测试

MySQL串行化隔离级别(间隙锁实现)

很明显,由于age>20的区间都被事务1加上了间隙锁(这里加的是共享锁),所以事务2插入age=22和age=21都失败了

MySQL串行化隔离级别(间隙锁实现)

幻读就是同一事务两次用相同的条件查询数据,下一次查出的数据量和上一次的数据量不一样,就算事务1把age=20的数据插入表,事务2再用age>20查询,得到的数据量也不会改变。

那事务1插入age=20的数据能否成功呢?

MySQL串行化隔离级别(间隙锁实现)


依然不能成功,这是因为我们插入的数据id是自增的,所以这条数据为(age=20,id=24),位于辅助索引树中(age=20,id=12)的右边,由于(age=20,id=12)右边都被上了锁,(age=20,id=24)自然无法插入。

辅助索引值相等的话。主键按升序排列。

MySQL串行化隔离级别(间隙锁实现)

很显然,事务1插入的age=18和age=19都不在事务2上锁的范围,所以可以插入

场景3:实际情况需要具体分析用的到底是行锁还是表锁

MySQL串行化隔离级别(间隙锁实现)

回滚,重新开启事务

MySQL串行化隔离级别(间隙锁实现)

开始测试

MySQL串行化隔离级别(间隙锁实现)

我们发现事务1无论是插入age>18范围内的数据,还是范围外的数据,都无法成功

这时我们就要分析了,这应该没有用到索引,因为我们用索引,过滤出的数据占了整张表的一大半,MySQL server没使用索引。

没有加行锁,只能加表锁(这时加的是共享锁),所以事务1无论插入什么数据都不行

MySQL串行化隔离级别(间隙锁实现)

果然,没有用到索引

MySQL串行化隔离级别(间隙锁实现)

age>20用到了索引,所以可以用行锁

三、测试间隙锁等值加锁

查看表结构和表数据

MySQL串行化隔离级别(间隙锁实现)

设置手动提交,设置串行化隔离级别,回滚然后启动事务

MySQL串行化隔离级别(间隙锁实现)

1. 测试不能重复的主键索引

此时事务2做select操作,由于是等值查询,所以给这条数据加了共享锁。

MySQL串行化隔离级别(间隙锁实现)

事务2的主键或者唯一键进行等值查询的时候,事务1插入一个新的数据是可以成功的,因为主键id不能重复,我们不能再插入主键id=9的数据。

MySQL串行化隔离级别(间隙锁实现)

在这种情况下,主键或者唯一键是不能重复的,事务2进行等值查询时,事务1插入一个新的数据,不用担心这条数据和查询条件是一样的,所以肯定能成功

2. 测试能重复的辅助索引

回滚并重启事务

MySQL串行化隔离级别(间隙锁实现)

事务2等值查询,给age=18这行数据加上了共享锁(record-lock)

MySQL串行化隔离级别(间隙锁实现)

这是一个等值查询,而且用的是辅助索引age,那么在辅助索引age的辅助索引树上叶子节点存的是age的辅助索引值和它所在行的主键值,

MySQL串行化隔离级别(间隙锁实现)

事务1插入age=18是不被允许的,否则事务2再查询age=18就有两条记录了。

MySQL串行化隔离级别(间隙锁实现)

奇怪的是,我们插入age=17,16,15也被阻塞住了

MySQL串行化隔离级别(间隙锁实现)

这是因为,为了防止幻读,除了age=18这条数据加了共享锁,其两侧也被加了间隙锁。

如果插入(age=15,id=1)就可以成功,根据辅助索引值相同,按照主键值升序排列,(age=15,id=1)应该放在(age=15,id=7)前面,不在间隙锁范围内

MySQL串行化隔离级别(间隙锁实现)

插入age=14,13都可以成功,不在间隙锁范围内。

MySQL串行化隔离级别(间隙锁实现)

间隙锁是给不存在的数据记录的范围加锁:

  • 对于辅助索引,若值允许重复,在串行隔离级别中如果进行等值查询,InnoDB会给数据加上行锁和间隙锁(防止别的事务插入索引值重复的数据,造成幻读)
  • 对于主键索引,或者唯一键索引,值不允许重复,那只需要加行锁就够了(对于唯一键索引,不可能发生插入索引值重复的数据)

到此这篇关于MySQL串行化隔离级别(间隙锁实现)的文章就介绍到这了,更多相关MySQL 间隙锁内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

MySQL 相关文章推荐
浅谈MySQL user权限表
Jun 18 MySQL
MySQL如何使用使用Xtrabackup进行备份和恢复
Jun 21 MySQL
python中的mysql数据库LIKE操作符详解
Jul 01 MySQL
MySql子查询IN的执行和优化的实现
Aug 02 MySQL
Mysql案例刨析事务隔离级别
Sep 25 MySQL
全面盘点MySQL中的那些重要日志文件
Nov 27 MySQL
mysql聚集索引、辅助索引、覆盖索引、联合索引的使用
Feb 12 MySQL
MySQL之MyISAM存储引擎的非聚簇索引详解
Mar 03 MySQL
mysql的Buffer Pool存储及原理
Apr 02 MySQL
MySQL数据库中的锁、解锁以及删除事务
May 06 MySQL
MySQL中order by的执行过程
Jun 05 MySQL
mysql幻读详解实例以及解决办法
Jun 16 MySQL
MySQL详解进行JDBC编程与增删改查方法
Jun 16 #MySQL
MySQL慢查询中的commit慢和binlog中慢事务的区别
Jun 16 #MySQL
MySQL聚簇索引和非聚簇索引的区别详情
关于mysql中string和number的转换问题
Jun 14 #MySQL
mysql实现将字符串字段转为数字排序或比大小
Jun 14 #MySQL
手把手带你彻底卸载MySQL数据库
MYSQL中文乱码问题的解决方案
Jun 14 #MySQL
You might like
PHP 裁剪图片成固定大小代码方法
2009/09/09 PHP
php中设置index.php文件为只读的方法
2013/02/06 PHP
[原创]PHP正则删除html代码中a标签并保留标签内容的方法
2017/05/23 PHP
js 函数的执行环境和作用域链的深入解析
2009/11/01 Javascript
js用Date对象处理时间实现思路及代码
2013/01/31 Javascript
JS判断是否360安全浏览器极速内核的方法
2015/01/29 Javascript
cookie的secure属性详解
2015/04/08 Javascript
js完美解决IE6不支持position:fixed的bug
2015/04/24 Javascript
javascript创建对象、对象继承的实用方式详解
2016/03/08 Javascript
Javascript设计模式之观察者模式(推荐)
2016/03/29 Javascript
JS/jQ实现免费获取手机验证码倒计时效果
2016/06/13 Javascript
原生js实现打字动画游戏
2017/02/04 Javascript
vue分类筛选filter方法简单实例
2017/03/30 Javascript
JS使用正则表达式验证身份证号码
2017/06/23 Javascript
javascript按顺序加载运行js方法
2017/12/01 Javascript
nodejs中实现修改用户路由功能
2019/05/24 NodeJs
[49:30]DOTA2-DPC中国联赛正赛 Dragon vs Dynasty BO3 第二场 3月4日
2021/03/11 DOTA
Django中几种重定向方法
2015/04/28 Python
Python实现的生成格雷码功能示例
2018/01/24 Python
Windows10下Tensorflow2.0 安装及环境配置教程(图文)
2019/11/21 Python
Python如何批量获取文件夹的大小并保存
2020/03/31 Python
python读取yaml文件后修改写入本地实例
2020/04/27 Python
英国家喻户晓的折扣商场:TK Maxx
2017/05/26 全球购物
女性时尚在线:IVRose
2019/02/23 全球购物
网络方面基础面试题
2012/11/16 面试题
专升本自我鉴定
2013/10/10 职场文书
车贷收入证明范本
2014/01/09 职场文书
早读迟到检讨书
2014/01/24 职场文书
优秀学生干部推荐材料
2014/02/03 职场文书
2015年化妆品销售工作总结
2015/05/11 职场文书
银行资信证明
2015/06/17 职场文书
2016年6.5世界环境日宣传活动总结
2016/04/01 职场文书
2019年年中工作总结讲话稿模板
2019/03/25 职场文书
女人创业励志语录,句句蕴含能量,激发你的潜能
2019/08/20 职场文书
深入解析Apache Hudi内核文件标记机制
2022/03/31 Servers
python模拟浏览器 使用selenium进入好友QQ空间并留言
2022/04/12 Python