1.结论

  在RR的隔离级别下,Innodb使用MVVC和next-key locks解决幻读,MVVC解决的是普通读(快照读)的幻读,next-key locks解决的是当前读情况下的幻读。

2.幻读是什么

事务A,先执行:

update table set name=“hh” where id>3;

结果为:

OK row xx 表名成功影响多少行数据

事务B,后执行,并且提交:

insert into table values(11, uu);

commit;

事务A,然后再select一下:

select * from table where id>3

结果集为:

11,uu

事务A懵了,我特么不是id>3全部更新了吗

这次是已提交事务B对事务A产生的影响,这个影响叫做“幻读”。

幻读和不可重复读的区别是,前者是一个范围,后者是本身

3. 怎么解决的?

3.1. 当前读

所谓当前读,指的是加锁的select(S或者X), update, delete等语句。在RR的事务隔离级别下,数据库会使用next-key locks来锁住本条记录以及索引区间。

拿上面那个例子来说,在RR的情况下,假设使用的是当前读,加锁了的读

select * from table where id>3 锁住的就是id=3这条记录以及id>3这个区间范围,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录。

3.2. 普通读

因为普通读是不会加锁的读,故不会有next-key locks的使用,解决幻读的手段是MVVC

mvvc会给每行元组加一些辅助字段,记录创建版本号和删除版本号。

而每一个事务在启动的时候,都有一个唯一的递增的版本号。每开启一个新事务,事务的版本号就会递增。

默认的隔离级别(REPEATABLE READ)下,增删查改变成了这样:

SELECT
读取创建版本小于或等于当前事务版本号,并且删除版本为空或大于当前事务版本号的记录。这样可以保证在读取之前记录是存在的
INSERT
将当前事务的版本号保存至行的创建版本号
UPDATE
新插入一行,并以当前事务的版本号作为新行的创建版本号,同时将原记录行的删除版本号设置为当前事务版本号
DELETE
将当前事务的版本号保存至行的删除版本号

  比如我插入一条记录, 事务id 假设是1 ,那么记录如下:也就是说,创建版本号就是事务版本号。

id

name

createversion

deleteversion

1 wxt 1  

  如果我更新的话,事务id假设是2

id

name

createverison

deleteversion

1 wxt 1 2
1 taotao 2  

  这里是把name更新为taotao,原来的元组deleteversion版本号为这个事务的id,并且新增一条

  如果我删除的话,假设事务是id=3

id

name

createverison

deleteversion

1 taotao 2 3

  重点来了

  现在我读取的话,必须同时满足两个条件的

  1. 读取创建版本小于或等于当前事务版本号   这意味着数据在这个事务之前被创建
  2. 删除版本为空或大于当前事务版本号的记录。  这意味着删除操作在这个事务之后发生

假设事务A的id=10

现在update table set name=“hh” where id>3;执行这条语句

事务B的id=11

insert into table values(11, uu);

最后事务A(id=10)在此读取

select * from table where id>3

根据上述的规则,

读取创建版本好小于等于当前事务的→那么(4,a)(5,b)(4,hh)(5,hh)

上面规则的输出作为下面规则的输入的话

删除版本为空或大于当前事务版本号的记录→(4,hh)(5,hh)

如此读取就没有读取到事务B新插入的那行,解决幻读。

如果事务B是更新id=4 的元组name=cc呢

同理,根据update的规则

然后根据select的规则去读取的话,得到的还是(4,hh)(5,hh)

参考:InnoDB怎么解决幻读的?

InnoDB在MySQL默认隔离级别下解决幻读的更多相关文章

  1. MYSQL事件隔离级别以及复读,幻读,脏读的理解

    一.mysql事件隔离级别 1未提交读(READUNCOMMITTED) 另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读)( 隔离级别最低,并发性能高 ) 2 ...

  2. sqlserver默认隔离级别下并发批量update同一张表引起的死锁

    提到死锁,最最常规的场景之一是Session1 以排它锁的方式锁定A表,请求B表,session2以排它锁的方式锁定B表,请求A表之类的,访问顺序不一致导致死锁的情况本文通过简化,测试这样一种稍显特殊 ...

  3. MySQL默认隔离级别为什么是RR

    曾多次听到“MySQL为什么选择RR为默认隔离级别”的问题,其实这是个历史遗留问题,当前以及解决,但是MySQL的各个版本沿用了原有习惯.历史版本中的问题是什么,本次就通过简单的测试来说明一下. 1. ...

  4. [原创]MySQL RR隔离级别下begin或start transaction开启事务后的可重复读?

    Server version:         5.6.21-log MySQL Community Server (GPL) 前提提要: 我们知道MySQL的RR(repeatable read)隔 ...

  5. MySQL的可重复读级别能解决幻读吗

    引言 之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了.但是对于幻 ...

  6. MySQL的可重复读级别能解决幻读问题吗?

    之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于幻读, ...

  7. 面试官:MySQL的可重复读级别能解决幻读问题吗?

    引言 之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于 ...

  8. Innodb 中 RR 隔离级别能否防止幻读?

    问题引出 我之前的一篇博客 数据库并发不一致分析 有提到过事务隔离级别以及相应加锁方式.能够解决的并发问题. 标准情况下,在 RR(Repeatable Read) 隔离级别下能解决不可重复读(当行修 ...

  9. InnoDB解决幻读的方案——LBCC&MVCC

    最近要在公司内做一次技术分享,思来想去不知道该分享些什么,最后在朋友的提示下,准备分享一下MySQL的InnoDB引擎下的事务幻读问题与解决方案--LBCC&MVCC.经过好几天的熬夜通宵,终 ...

随机推荐

  1. Hadoop学习(9)-spark的安装与简单使用

    spark和mapreduce差不多,都是一种计算引擎,spark相对于MapReduce来说,他的区别是,MapReduce会把计算结果放 在磁盘,spark把计算结果既放在磁盘中有放在内存中,ma ...

  2. java-极光推送教程

    一.准备工作: 1.访问极光推送官网:https://www.jiguang.cn/accounts/login/form 2.注册登陆,拿到appKey和masterSecret 3.创建一个应用, ...

  3. 逆向破解之160个CrackMe —— 002-003

    CrackMe —— 002 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...

  4. react学习(一)--JSX简介

    由于在中国银联实习的项目要用到react,所以不得不硬着头皮把react学习一下.这是要往全栈发展吗0.0 正文: 一个最简单的React例子如下, ReactDOM.render( <h1&g ...

  5. SpringBoot中读取配置文件的几种方式

    1.读取application文件 在application.yml或者properties文件中添加: info: name: xiaoming age: 13 sex: 1 读取方式如下: imp ...

  6. docker 容器之间互联

    容器之间的互联 一. 实验目的: 1.       熟悉容器之间基本的网络原理: 2.       掌握容器之间互联的方法: 二. 实验环境: Ubuntu16.04+Docker 三. 实验内容: ...

  7. Flink 源码解析 —— Flink JobManager 有什么作用?

    JobManager 的作用 https://t.zsxq.com/2VRrbuf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...

  8. AutoResetEvent控制线程用法

    本文主要来自一道面试题,由于之前对AutoResetEvent的用户很模糊(即使已经使用过了).面试题题目很简洁:两个线程交替打印0~100的奇偶数.你可以先动手试试,我主要是尝试在一个方法里面完成这 ...

  9. PostgreSQL数据库查询最近几天的数据

    pgsql语法类似mysql  ,下面总结几个pgsql工作会用到的求时间的语句 1.当前时间向前推一天\ SELECT current_timestamp - interval '1 day' 例: ...

  10. git 导出新修改的文件

    git archive -o update.zip HEAD $(git diff --name-only HEAD)