MySQL面试三连杀:如何实现可重复读、又为什么会出现幻读、是否解决了幻读问题?...
作者 | sanyuesan0000
来源 | https://blog.csdn.net/sanyuesan0000
事务隔离级别有四种,mysql默认使用的是可重复读,mysql是怎么实现可重复读的?为什么会出现幻读?是否解决了幻读的问题?
一、事务的隔离级别
Read Uncommitted(未提交读)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。读取未提交的数据,也被称之为脏读(Dirty Read)。该级别用的很少。
Read Committed(提交读)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变,换句话说就是事务提交之前对其余事务不可见。
这种隔离级别也支持不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select查询可能返回不同结果。
Repeatable Read(可重复读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。
简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。
InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题(mysql彻底解决了幻读问题?请往下看)。
Serializable(可串行化)
这是最高的隔离级别,它强制事务都是串行执行的,使之不可能相互冲突,从而解决幻读问题。换言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
3年至少15个项目经验,7天搞定1个项目!这样的招聘要求,你能胜任吗?
在MySQL的众多存储引擎中,只有InnoDB支持事务,所有这里说的事务隔离级别指的是InnoDB下的事务隔离级别。
二、mysql怎么实现的可重复读
MVCC多版本并发控制(Multi-Version Concurrency Control)是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现读已提交和可重复读取隔离级别。
在《高性能MySQL》中对MVCC的解释如下
MyBatis 的执行流程,写得太好了!
举例说明MVCC的实现
新建一张表test_zq如下
MVCC逻辑流程-插入
在插入数据的时候,假设系统的全局事务ID从1开始,以下SQL语句执行分析参考注释信息:
begin;-- 获取到全局事务ID
insert into `test_zq` (`id`, `test_id`) values('5','68');
insert into `test_zq` (`id`, `test_id`) values('6','78');
commit;-- 提交事务
当执行完以上SQL语句之后,表格中的内容会变成:
有些人一眼就能认出来,你认出来几个?
可以看到,插入的过程中会把全局事务ID记录到列 DB_TRX_ID 中去
MVCC逻辑流程-删除
对上述表格做删除逻辑,执行以下SQL语句(假设获取到的事务逻辑ID为 3)
begin;--获得全局事务ID = 3
delete test_zq where id = 6;
commit;
执行完上述SQL之后数据并没有被真正删除,而是对删除版本号做改变,如下所示:
请立即卸载这款 IDEA 插件
MVCC逻辑流程-修改
修改逻辑和删除逻辑有点相似,修改数据的时候 会先复制一条当前记录行数据,同事标记这条数据的数据行版本号为当前是事务版本号,最后把原来的数据行的删除版本号标记为当前是事务。
执行以下SQL语句:
begin;-- 获取全局系统事务ID 假设为 10
update test_zq set test_id = 22 where id = 5;
commit;
执行后表格实际数据应该是:
Spring Security 干货:WebSecurity和HttpSecurity的关系
MVCC逻辑流程-查询
此时,数据查询规则如下:
查找数据行版本号早于当前事务版本号的数据行记录
也就是说,数据行的版本号要小于或等于当前是事务的系统版本号,这样也就确保了读取到的数据是当前事务开始前已经存在的数据,或者是自身事务改变过的数据
查找删除版本号要么为NULL,要么大于当前事务版本号的记录
这样确保查询出来的数据行记录在事务开启之前没有被删除
根据上述规则,我们继续以上张表格为例,对此做查询操作
begin;-- 假设拿到的系统事务ID为 12
select * from test_zq;
commit;
执行结果应该是:
“12306” 是如何支撑百万 QPS 的?
这样,同一个事务中,就实现了可重复读。
三、幻读
什么是幻读,如下:
5天5000万访问的个人网站是如何诞生的?
InnoDB实现的RR通过mvcc机制避免了这种幻读现象。
另一种幻读:
阿里面试:索引失效的场景有哪些?索引何时会失效?
姑且把左边的事务命名为事务A,右边的命名为事务B。
事务B执行后,在事务A中查询没有查到B添加的数据行,这就是可重复读。
但是,在事务A执行了update后,再查询时就查到了事务A中添加的数据,这就是幻读。
这种结果告诉我们其实在MySQL可重复读的隔离级别中并不是完全解决了幻读的问题,而是解决了读数据情况下的幻读问题。而对于修改的操作依旧存在幻读问题,就是说MVCC对于幻读的解决是不彻底的。
原以为这也是一种幻读,但经过多次研究资料,这只是对数据修改的操作(update、insert、delete)当前读产生的结果,他其实不是幻读。
快照读和当前读
出现了上面的情况我们需要知道为什么会出现这种情况。在查阅了一些资料后发现在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,不是数据库最新的数据。这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库最新版本数据的方式,叫当前读 (current read)。
select 快照读
当执行select操作是innodb默认会执行快照读,会记录下这次select后的结果,之后select 的时候就会返回这次快照的数据,即使其他事务提交了不会影响当前select的数据,这就实现了可重复读了。
快照的生成当在第一次执行select的时候,也就是说假设当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据。之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。
当前读
对于会对数据修改的操作(update、insert、delete)都是采用当前读的模式。在执行这几个操作时会读取最新的版本号记录,写操作后把版本号改为了当前事务的版本号,所以即使是别的事务提交的数据也可以查询到。
假设要update一条记录,但是在另一个事务中已经delete掉这条数据并且commit了,如果update就会产生冲突,所以在update的时候需要知道最新的数据。也正是因为这样所以才导致幻读。
四、如何解决幻读
在快照读情况下,mysql通过mvcc来避免幻读。
在当前读情况下,mysql通过X锁或next-key来避免其他事务修改:
使用串行化读的隔离级别
(update、delete)当where条件为主键时,通过对主键索引加record locks(索引加锁/行锁)处理幻读。
(update、delete)当where条件为非主键索引时,通过next-key锁处理。next-key是record locks(索引加锁/行锁) 和 gap locks(间隙锁,每次锁住的不光是需要使用的数据,还会锁住这些数据附近的数据)的结合。
3年至少15个项目经验,7天搞定1个项目!这样的招聘要求,你能胜任吗?
Next-Key Lock即在事务中select时使用如下方法加锁,这样在另一个事务对范围内的数据进行修改时就会阻塞(为什么有共享锁会阻塞?不能在有共享锁的记录上加X锁):
select * from table where id<6 lock in share mode;--共享锁
select * from table where id<6 for update;--排他锁
参考文章
https://juejin.im/post/5c68a4056fb9a049e063e0ab
https://zhuanlan.zhihu.com/p/35500144
https://www.jianshu.com/p/69fd2ca17cfd
https://blog.csdn.net/AAA821/article/details/81017704
https://dbaplus.cn/news-11-2518-1.html
《高性能MySQL》
往期推荐
3年至少15个项目经验,7天搞定1个项目!这样的招聘要求,你能胜任吗?
请立即卸载这款 IDEA 插件
“12306” 是如何支撑百万 QPS 的?
还在用Logback?Log4j2的异步性能已经无敌了,还不快试试
5天5000万访问的个人网站是如何诞生的?
如果你喜欢本文,欢迎关注我,订阅更多精彩内容
关注我回复「加群」,加入Spring技术交流群
免费领取:机器学习、深度学习实践宝典
喜欢的这里报道
↘↘↘
MySQL面试三连杀:如何实现可重复读、又为什么会出现幻读、是否解决了幻读问题?...相关推荐
- 揭秘Mysql事务隔离级别之可重复读
揭秘Mysql事务隔离级别之可重复读 1.可重复读的来源 2.何为不可重复读 3.那么可重复读和不可重复读究竟有什么关系呢? 4.模拟不同事务隔离级别对不可重复的处理情况(有线程执行顺序). 4.1. ...
- Mysql-可重复读的隔离级别在什么情况下会出现幻读
目录 一.常见说法的不准确 二.结论 三.实验验证 现象 0:事务 1 两次 select 一样且事务 1 两次 select 间没有额外操作,可以防止幻读 现象 1:事务 1 的第 2 次selec ...
- mysql 可重复读 悲观锁_一文带你理解脏读,幻读,不可重复读与mysql的锁,事务隔离机制...
首先说一下数据库事务的四大特性 1 ACID 事务的四大特性是ACID(不是"酸"....) (1) A:原子性(Atomicity) 原子性指的是事务要么完全执行,要么完全不执行 ...
- Mysql如何实现隔离级别 - 可重复读和读提交 源码分析
Abstract 本文会(1) 演示Mysql的两种隔离级别. (2) 跟着mysql的源代码来看看它是怎么实现这两种隔离级别的. Mysql的隔离级别 当有多个事务并发执行时, 我们需要考虑他们之 ...
- MySQL事务隔离级别:可重复读、读已提交、读未提交。实操
MySQL的事务隔离级别: 目录 一.可重复读(默认) REPEATABLE-READ: 二.读已提交 READ-COMMITTED: 一.可重复读(默认) REPEATABLE-READ: 准备实 ...
- MySQL理论:脏读、不可重复读、幻读
文章目录 1. 脏读(dirty read) 脏读是指事务读取到其他事务未提交的数据 2. 不可重复读(non-repeatable read) 不可重复读是指在同一次事务中前后查询不一致的问题 3. ...
- MySQL锁与脏读、不可重复读、幻读详解
一.MySQL锁 1.锁简介 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据 ...
- mysql幻读和不可重复读的区别_面试官:MySQL的可重复读级别能解决幻读吗
Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...
- 不可重复读和幻读的区别_面试官:MySQL的可重复读级别能解决幻读吗
Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...
最新文章
- 【GLib】GLib学习笔记(一):GLib、GObject、GType
- index.php user r,安装cms :在浏览器中打开http://你的网址/install/index.php 出现白屏怎样处理?...
- 原型模式(Prototype)
- [原]关于鼠标滚轮的编程
- 【控制】多智能体系统总结。4.控制协议。
- access 日期交集_Access重要知识点
- 第十章 优先级队列 (b3)完全二叉堆:删除与下滤
- 【UI自动化测试】Mac下进行Monkey测试
- 每个tabpage中都有一个dategridview_其实每个人都是一个孩子,仅此而已
- linux下screen版本,在Linux (RHEL/CentOS 7/8 )中,如何使用4个简单步骤安装Screen命令
- LIBCMTD.lib与libcpmtd冲突的解决方法。
- 漫步数学分析三十四——链式法则
- 移动端页面rem+media写法过程
- 关于embedding的理解,2020-7-30
- DVWA系列之11 Brute Force中的密码绕过
- Java中的native方法的使用
- Java ftp 上传文件名乱码
- ntp server
- 静态背景下运动目标检测 matlab_基于深度学习的视频目标检测综述
- 由点及面,一叶知秋------集合大家庭
热门文章
- Silverlight 和WPF的Composite Guidance(Prism V2)发布了
- Linux下运行java DES解密失败,报javax.crypto.BadPaddingException:Given final block not properly padded
- linux 修改 ko文件内核版本号
- java 反序列化漏洞 利用思路简介
- linux shell mkdosfs 命令用于建立 dos 文件系统
- linux 服务不支持 chkconfig 的解决方法
- centos7 yum 安装 redis
- linux VFS 虚拟文件系统 简介 super_block inode dentry file
- linux c 打印错误信息error errno perror和strerror的区别
- 数组排序方法及C实现的总结