作者 | 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面试三连杀:如何实现可重复读、又为什么会出现幻读、是否解决了幻读问题?...相关推荐

  1. 揭秘Mysql事务隔离级别之可重复读

    揭秘Mysql事务隔离级别之可重复读 1.可重复读的来源 2.何为不可重复读 3.那么可重复读和不可重复读究竟有什么关系呢? 4.模拟不同事务隔离级别对不可重复的处理情况(有线程执行顺序). 4.1. ...

  2. Mysql-可重复读的隔离级别在什么情况下会出现幻读

    目录 一.常见说法的不准确 二.结论 三.实验验证 现象 0:事务 1 两次 select 一样且事务 1 两次 select 间没有额外操作,可以防止幻读 现象 1:事务 1 的第 2 次selec ...

  3. mysql 可重复读 悲观锁_一文带你理解脏读,幻读,不可重复读与mysql的锁,事务隔离机制...

    首先说一下数据库事务的四大特性 1 ACID 事务的四大特性是ACID(不是"酸"....) (1) A:原子性(Atomicity) 原子性指的是事务要么完全执行,要么完全不执行 ...

  4. Mysql如何实现隔离级别 - 可重复读和读提交 源码分析

    Abstract 本文会(1) 演示Mysql的两种隔离级别.  (2) 跟着mysql的源代码来看看它是怎么实现这两种隔离级别的. Mysql的隔离级别 当有多个事务并发执行时, 我们需要考虑他们之 ...

  5. MySQL事务隔离级别:可重复读、读已提交、读未提交。实操

    MySQL的事务隔离级别: 目录 一.可重复读(默认) REPEATABLE-READ: 二.读已提交  READ-COMMITTED: 一.可重复读(默认) REPEATABLE-READ: 准备实 ...

  6. MySQL理论:脏读、不可重复读、幻读

    文章目录 1. 脏读(dirty read) 脏读是指事务读取到其他事务未提交的数据 2. 不可重复读(non-repeatable read) 不可重复读是指在同一次事务中前后查询不一致的问题 3. ...

  7. MySQL锁与脏读、不可重复读、幻读详解

    一.MySQL锁 1.锁简介 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据 ...

  8. mysql幻读和不可重复读的区别_面试官:MySQL的可重复读级别能解决幻读吗

    Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...

  9. 不可重复读和幻读的区别_面试官:MySQL的可重复读级别能解决幻读吗

    Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:宁愿. 来源:https://juejin.im/post/5c9040e95188252d92095a9e 引言 之前 ...

最新文章

  1. 【GLib】GLib学习笔记(一):GLib、GObject、GType
  2. index.php user r,安装cms :在浏览器中打开http://你的网址/install/index.php 出现白屏怎样处理?...
  3. 原型模式(Prototype)
  4. [原]关于鼠标滚轮的编程
  5. 【控制】多智能体系统总结。4.控制协议。
  6. access 日期交集_Access重要知识点
  7. 第十章 优先级队列 (b3)完全二叉堆:删除与下滤
  8. 【UI自动化测试】Mac下进行Monkey测试
  9. 每个tabpage中都有一个dategridview_其实每个人都是一个孩子,仅此而已
  10. linux下screen版本,在Linux (RHEL/CentOS 7/8 )中,如何使用4个简单步骤安装Screen命令
  11. LIBCMTD.lib与libcpmtd冲突的解决方法。
  12. 漫步数学分析三十四——链式法则
  13. 移动端页面rem+media写法过程
  14. 关于embedding的理解,2020-7-30
  15. DVWA系列之11 Brute Force中的密码绕过
  16. Java中的native方法的使用
  17. Java ftp 上传文件名乱码
  18. ntp server
  19. 静态背景下运动目标检测 matlab_基于深度学习的视频目标检测综述
  20. 由点及面,一叶知秋------集合大家庭

热门文章

  1. Silverlight 和WPF的Composite Guidance(Prism V2)发布了
  2. Linux下运行java DES解密失败,报javax.crypto.BadPaddingException:Given final block not properly padded
  3. linux 修改 ko文件内核版本号
  4. java 反序列化漏洞 利用思路简介
  5. linux shell mkdosfs 命令用于建立 dos 文件系统
  6. linux 服务不支持 chkconfig 的解决方法
  7. centos7 yum 安装 redis
  8. linux VFS 虚拟文件系统 简介 super_block inode dentry file
  9. linux c 打印错误信息error errno perror和strerror的区别
  10. 数组排序方法及C实现的总结