精华内容
下载资源
问答
  • 可重复读能解决幻读吗
    2021-01-20 02:56:25

    转载地址 https://blog.csdn.net/leisurelen/article/details/108436815

    在MYSQL的RR隔离级别下, MYSQL也解决了幻读的问题。 主要是依靠两个特性解决的, 一个是MVCC(一致性快照) 一个是间隙锁。

    MVCC如何解决幻读

    begin

    select count(*) from table where id >10...... 一系列的其他操作 ......select count(*) from table where id >10

    commit

    上面的sql 语句如果在执行的过程中(中间的一系列操作中), 其他的事务新增了 id>10 的记录, 这个sql语句的前后两次查询记录的条数的结果还是一样的。

    为何会这样是因为MYSQL的MVCC机制, 在事务开始的时候, 其实已经创建了一个快照, 后面的所有查询都是查询这个快照的, 所以查询结果一样,

    至于MVCC的机制是如何作用的, MYSQL主要是记住各个事务的id, 并根据每行数据的事务id来进行比较来确定版本快照的, 具体机制大家可以搜下。

    如果我们把语句改成这样呢?

    1 begin

    2 select count(*) from table where id >10 for update

    3 ...... 一系列的其他操作 ......4 select count(*) from table where id >10 for update

    5 commit

    由于for update 的特性导致这个查询语句是使用的当前读, 并没有使用快照。 那么快照就不能保证解决幻读问题了。 这个时候就要用上间隙锁的概念了。

    间隙锁保证幻读正确

    begin

    select count(*) from table where id >10 for update## 10前面的一条记录的id就是9

    ...... 一系列的其他操作 ......select count(*) from table where id >10 for update

    commit

    这个sql的事务在执行到第一个查询语句的时候, 会加上间隙锁的, 锁住的范围是(9,+无穷] . 那么其他的事务无法再这个id范围进行任何的修改和插入操作了, 他们如果要操作就会堵住。

    这样mysql又通过间隙锁的功能解决了幻读问题,但是可以看到这个代价很大的, 仅次于全表写锁了。

    间隙锁的死锁问题

    正常的读写锁之间的互斥关系我们很清楚,但是间隙锁呢, 间隙锁与间隙锁之间是不互斥的。 就是一个事务A锁住了(0,100]的间隙锁,那么B事务也可以重复获取(0,100]的间隙锁。

    上面两个事务都获取了间隙锁, 这个时候如果A事务要在这个间隙之间插入一条记录,会阻塞,因为B事务间隙锁了, 同样B事务也不能操作这个间隙了。 这样就导致了两个线程形成死锁了。

    这就是代价,是InnoDB解决幻读的代价。

    更多相关内容
  • 主要给大家介绍了关于MySQL可重复读级别能否解决幻读的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • 可重复读:同一事务内,不同时刻读到的同一批数据可能不一样 幻读:对于插入来说的,事务A按照一定条件进行数据读取,期间事务B插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现事务B新...

    事务及事务隔离级别

    innodb存储引擎支持事务,myisam不支持事务

    事务内的操作要么全部成功,要么全部失败,中途有失败则回滚

    事务的ACID:原子性,一致性,隔离性,持久性

    事务隔离级别需要解决的问题:

    • 脏读:读到其他事务未提交的事务

    • 不可重复读:同一事务内,不同时刻读到的同一批数据可能不一样

    • 幻读:对于插入来说的,事务A按照一定条件进行数据读取,期间事务B插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现事务B新插入的数据

    事务隔离级别:

    • 读未提交

    • 读提交

    • 可重复读(默认隔离级别)

    • 串行化

    从上至下隔离强度逐渐增强

    读未提交:不加锁,连脏读问题都解决不了

    读提交:解决了脏读,但是还有不可重复读的问题。因为可能某个事务查询期间,有另一个事务修改并提交了数据,则可能导致同一事务两次数据读到的不一样。

    可重复读:事务不会读到其他事务对已有数据的修改,事务开始有什么数据,那么事务提交前的任意时刻,数据都是一样的。但是,对于事务新插入的数据是可以读到的,这也就是幻读的问题。但是需要强调的是,MySQL的可重复读其实解决了幻读的问题。

    串行化:问题都解决了,但是将事务的执行变为了顺序查询,相当于当线程。

    MySQL如何实现事务隔离级别?

    读未提交:不加锁,可以理解为没有隔离。

    串行化:读的时候加共享锁,写的时候加排他锁。

    剩下的两个既要允许一定的并发,又要解决一些问题,因此比较复杂。

    MVCC

    MySQL采用MVCC(多版本并发控制)的方式,实现读提交和可重复读

    对于一个快照来说,能读到哪些基于以下规则:

    1. 当前事务内的更新,可以读到

    2. 版本未提交,不能读到

    3. 版本已提交,但是在快照创建后提交的,不能读到。

    4. 版本已提交,且是在快照创建前提交的,可以读到。

    对于快照读(select)

    对于读提交,每次进行快照读时都会生成最新的Read View

    对于可重复读,只有事务开始的第一个快照读会创建Read View

    对于当前读(update,insert,delete)

    行锁加间隙锁来解决,这个合并的锁叫做Next-Key锁

    在修改的记录两边的区间加上间隙锁。

    这里需要注意一个问题,加锁的过程要分为有索引和无索引两种情况,有索引时,直接通过索引找到数据行,直接加锁。对于没有索引的,会为这张表所有行加上锁,不满足条件的释放锁,留下满足条件的,会极大影响性能。

    漏洞?:默认隔离级别(可重复读)

    1. 事务A select

    2. 事务B insert

    3. 事务B commit

    4. 事务A select(与第一次select的结果一样)

    5. 事务A update 所有行

    6. 事务A select(会发现多出了事务B insert 的行)

    这算出现了幻读吗?

    所以说MVCC并不能完美解决RR下的幻读问题??

    一旦事务A的修改操作覆盖到了其他事务插入的“幻行”,那么在下次select的时候,也会把这行数据一起查出来

    要解释这个现象,需要深入理解MVCC

    隐藏字段

    1. DB_TRX_ID(6字节):表示最近一次对本记录行作修改(insert | update)的事务ID。至于delete操作,InnoDB认为是一个update操作,不过会更新一个另外的删除位,将行表示为deleted。并非真正删除。

    1. DB_ROLL_PTR(7字节):回滚指针,指向当前记录行的undo log信息

    2. DB_ROW_ID(6字节):随着新行插入而单调递增的行ID。理解:当表没有主键或唯一非空索引时,innodb就会使用这个行ID自动产生聚簇索引。如果表有主键或唯一非空索引,聚簇索引就不会包含这个行ID了。

    Read View结构

    low_limit_id:目前出现过的最大的事务ID+1,即下一个将被分配的事务ID

    up_limit_id:活跃事务列表trx_ids中最小的事务ID,如果trx_ids为空,则up_limit_id 为 low_limit_id

    trx_ids:Read View创建时其他未提交的活跃事务ID列表。

    creator_trx_id:当前创建事务的ID,是一个递增的编号

    比较算法

    db_trx_id < up_limit_id || db_trx_id == creator_trx_id(显示)

    如果数据事务ID小于read view中的最小活跃事务ID,则可以肯定该数据是在当前事务启之前就已经存在了的,所以可以显示。

    或者数据的事务ID等于creator_trx_id ,那么说明这个数据就是当前事务自己生成的,自己生成的数据自己当然能看见,所以这种情况下此数据也是可以显示的。

    db_trx_id >= low_limit_id(不显示)

    如果数据事务ID大于read view 中的当前系统的最大事务ID,则说明该数据是在当前read view 创建之后才产生的,所以数据不显示。如果小于则进入下一个判断

    db_trx_id是否在活跃事务(trx_ids)中

    不存在:则说明read view产生的时候事务已经commit了,这种情况数据则可以显示。

    已存在:则代表我Read View生成时刻,你这个事务还在活跃,还没有Commit,你修改的数据,我当前事务也是看不见的。

    实际例子

     

    对应的事务10003的实际运行的三次select(原始数据id=1,age=19)

     

    那么这个叫出现了幻读吗?

    快照读和当前读混用造成的异常,不能算是出现了幻读

    当前读的效果就是要读取最新版本,实际上是把隔离级别从 repeatable-read 降级到了 read-committed,所以快照读和当前读混用不算幻读。

    img

    我们是不是得说这个例子说明了 repeatable-read 允许“不可重复读异常现象”?显然不能。对于不可重复读异常,repeatable-read 隔离级别是明确不允许的。这就说明了当前读和快照读混用带来的异常不能称为幻读。

    总结:

    1. MVCC能实现快照读的可重复读,不会出现不可重复读和幻读

    2. 间隙锁加行锁(或者说Next-Key锁),实现当前读的可重复读,也不会出现不可重复读和幻读

    3. 快照读和当前读混用造成的异常,不能算是出现了幻读

    展开全文
  • 可重复读如何解决幻读

    千次阅读 2020-02-19 16:07:43
    可重复读的概念 与 不可重复读的概念 行锁+gap锁(间隙锁) 快照读 与 当前读区别 快照读中的MVCC 和 乐观锁 当前读中的gap锁 和 悲观锁

    学习之前的疑问:
    可重复读的概念 与 不可重复读的概念
    行锁+gap锁(间隙锁)
    快照读 与 当前读区别
    快照读中的MVCC
    当前读中的gap锁 和 行锁

    前几天面试时被问到了mysql可重复读如何解决幻读的问题,之前脑子中的概念只有增加了共享锁和排他锁进行避免,没有实践或者清晰的概念,今天首先实践验证和理解mysql下可重复读对于幻读的避免和原理。参考博文:https://blog.csdn.net/Y0Q2T57s/article/details/103708206

    首先整体了解数据库的隔离级别:

    读未提交 -------------- 可能产生脏读,幻读,不可重复读
    读已提交(不可重复读)----------------- 可能产生不可重复读,幻读
    可重复读 ---------------------------------可能产生幻读
    序列化 -----------------------------------无

    可重复度和不可重复读

    • 概念:
    1. 不可重复读指的是事务1和事务2同时获取数据,在此时事务2进行插入行或者修改行操作,这时事务1再次进行select时会发现多了几行数据或者数据不一致,这就称为幻读
    2. 可重复读,也就是在RR隔离级别下,为了避免不可重复读的幻读情况发生,事务2修改数据的结果 在事务1是无法获取的,进行了隔离,这个实现后面会介绍到MVCC。

    在了解了mysql的几个隔离级别后,针对可重复读是如何防止产生幻读的?

    • 先来通过实践验证简单的:如何防止如不可重复读的情况
      首先创建一张表
    Create Table: CREATE TABLE `dept` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8
    

    开启两个事务
    在这里插入图片描述
    表中没有数据,现在我们往右边事务中插入一条数据,如果在不可重复的隔离级别下在左边事务再select会发现新插入数据,而可重复读的情况下左边的select数据一直不变。
    在这里插入图片描述

    • 解释:这一现象的原理是RR即可重复读的隔离级别下用到了MVCC,多版本并发控制,每个事务在开启时会有一个版本号,不管其他事务如何数据,而当前事务中的版本号不会变化,所以左边事务一直select的数据都是一个版本中的,所以不会读取到右边事务插入后的数据。
    在左边事务中发现内容为空,我们插入一个id=29的数据行,看看会发生什么

    在这里插入图片描述

    • 解释:这是什么情况呢?这是因为在select时会使用到快照读,但是在例如上面insert时会进行当前读, 如字面意思解释,快照读即事务开启时产生的版本号一般,进行了数据表当前的数据“复制”,在事务中select时只会用到快照读,但是如果进行insert/ update / select … for update 这种语句时,会进行当前读,访问数据表中“最新”的数据,这时尽管右边的insert未提交,但当前读还是会读到, 那么根据报错的信息,lock,得知在右边事务insert一行之后会进行加锁 (X锁),不允许其他事务修改,但能读取当前数据(当前读)即获取当前行的S锁,左边insert需要在右边事务释放锁之后才能进行insert/update操作(commit或者rollback)

    下面对X锁和S锁进行学习

    • X锁称为排他锁(悲观锁) ----- 对目标行添加当前事务的X锁,即可修改或删除操作
    • S锁称为共享锁(共享锁) ----- 对目标行添加当前事务的S锁,即可读当前行的数据
      S锁是可以兼容的,即多个事务都可以持有对某行的读权限, 而X锁是不兼容的,即最多只有一个事务能获取当前行的修改或删除权限, 若其他事务需要获取X锁,必须等当前拥有X锁权限的事务释放X锁才能获取。

    而上面出现的情况是因为 右边事务在Insert时便对id=29的行数据添加了X锁,而这时左边事务要对id=29的行进行X操作,那么首先需要获取已经被右边事务拥有的X锁,那么需要等右边事务释放X锁权限(commit或者rollback)才能获取.

    • 还有如下情况: 在这里插入图片描述
      如上面解释,如果右边事务插入id=99的数据行,如果左边事务修改id范围不包含99的话应该可以操作,但是左边事务也遇到了锁,导致不能修改成功,这是因为上面的X锁不仅包含了当前一行,还有(-无穷大, 10) 和 (10,+无穷大)加锁, 在左边事务update时,会遇到间隙锁(GAP锁),导致需要等待右边事务释放锁后才能更新。

    通过上面可重复读中几种情况,总结:可重复读本身还是存在幻读的,但是因为在可重复读上添加了NEXE-KEY锁(即行锁+gap锁)避免了幻读的产生。

    展开全文
  • MVCC解决可重复读幻读了吗?

    一、概览

    MVCC在一定程度可以避免幻读,但是不能完全解决幻读

    二、举例说明什么是幻读,重现幻读现象

    什么是幻读

    把读写事务出现的三个问题再回顾一下

    脏读:事务A读取到事务B未提交的数据,此时为脏读。
    不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。
    幻读:事务A以同种条件先后查询数据库,两次查询结果的条数不同,这种现象称为幻读。

    脏读和不可重复读的区别:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据
    不可重复读与幻读的区别:前者是数据变了,后者是数据的行数变了。

    举例说明幻读

    首先设置事务A为读已提交隔离级别。
    在这里插入图片描述

    三、举例说明可以一定程度上解决幻读

    现在设置事务A的隔离级别为可重复读
    在这里插入图片描述
    前面我们将MVCC实现可重复读原理中提到,读分为快照读和当前读(或者叫加锁读)。当前读就是写操作需要先读取最新的数据然后再写,写的过程是加锁的。

    列举下快照读和当前读的操作。

    1. 快照读(snapshot read)
    简单的select操作(不包括 select ... lock in share mode, select ... for update)
        
    2.当前读(current read)
    select ... lock in share mode
    select ... for update
    insert
    update
    delete
    

    因此在可重复读的时候,读的是快照中的数据,即ReadView中的数据,也就是历史数据。

    那么为什么读已提交会产生幻读现象呢?

    因为在RC(读已提交)隔离级别下,是每个快照读都会生成并获取最新的Read View;而在RR(可重复读)隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View。

    四、举例说明没有完全解决幻读

    RR虽然避免了幻读问题,但是毕竟不是Serializable,不能保证完全的隔离

    如果在事务中第一次读取采用快照读,第二次读取采用当前读,则如果在两次读取之间数据发生了变化,两次读取到的结果不一样,因为加锁读时不会采用MVCC。如下例子

    在这里插入图片描述

    所以从以上实验中就可以得出MVCC在一定程度可以避免幻读,但是不能完全解决幻读

    展开全文
  • 但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理? 测试: 创建一张测试用的表dept: CREATE TABLE `dept` ( `id` int(11) NOT NULL AUTO_IN
  • 之前在深入了解数据库理论的时候,...但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理?测试:创建一张测试用的表dept:CREATE TABLE `dept` (`id` int(11) NOT NULL ...
  • 关于数据库的隔离级别标准的定义是在可重复读级别下可能发生幻读,解决幻读只有使用序列化。虽然标准是这样说但是数数据库实现的隔离级别可能会和标准有点出入。关于这方面的讨论在DDIA中有一些讨论。 关于MySQL...
  • MySQL的可重复读级别能解决幻读

    千次阅读 2020-01-05 15:17:23
    引言 之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题。为了更好的理解所以在...但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理? 测试:...
  • 可重复读隔离级别能解决幻读? 三.什么是当前读和快照读? 四.MVCC的实现原理 五.RC,RR级别下的InnoDB快照读有什么不同? 六.如何解决幻读 七.事务是么时候开始 MySQL可重复读隔离级别为何没有解决幻读(MVCC...
  • 数据库的脏读、不可重复读幻读都和事务的隔离性有关。所以先了解一下事务的4大特性。  事务的4大特性(ACID):  1、原子性(Atomicity):事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么...
  • mysql可重复读幻读的理解可重复读幻读的定义最后总结参考资料 很多教程和书籍对mysql的可重复读幻读的解释都比较含糊,本文结合原理和其他的考证,深入分析下。 这里讨论的引擎是常用的InnoDB。 可重复读...
  • MySQL 可重复读隔离级别与幻读

    千次阅读 2022-03-16 17:40:02
    在MySQL可重复读的隔离级别下,很大程度上避免幻读,而不完全避免。 场景复现 环境信息: MySQL版本:5.7.23-log 隔离级别:REPEATABLE-READ 测试数据: SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; --...
  • 我们先来回忆下相关的概念:事务隔离级别读未提交(READ UNCOMMITTED)事务中的修改,即使没有提交,对其他事务都是可见的,会产生脏读、不可重复读幻读问题。读已提交(READ COMMITTED)一个事务开始时,只能看见已经...
  • Mysql可重复读隔离级别下如何解决幻读一些概念具体加锁说明使用主键索引进行等值查询使用主键索引进行范围查询使用二级索引进行等值查询使用二级索引进行范围查询 一些概念 幻读:在一次事务中,同一条select语句在...
  • 幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。...
  • 文章目录可重复读(Repeatable read)防住幻读吗?事务隔离级别事务的并发问题概念幻读和不可重复读的区别乐观锁与悲观锁悲观锁乐观锁数据版本MVCC当前读Next-Key锁 可重复读(Repeatable read)防住幻读吗? ...
  • 很明显可重复读的隔离级别没有办法彻底的解决幻读的问题,如果我们的项目中需要解决幻读的话也有两个办法: 使用串行化读的隔离级别 MVCC+next-key locks:next-key locks由record locks(索引加锁) 和 gap locks...
  • 我不管从数据库方面的教科书还是一些网络教程上,经常看到RR级别是可以重复读的,但是无法解决幻读,只有串行化(Serializable)才能解决幻读,这个说法是否正确呢? 在这篇文章中,我将重点围绕MySQL中可重复读...
  • 脏读 一个事务访问到了其他事务未提交的数据更改 例:事务A对一个数据进行了修改操作,但事务A未提交,...不可重复读 在一个事务中进行了两次查询操作,得到的数据内容不一致 例:事务A进行两次查询操作,在两次
  • 我不管从数据库方面的教科书还是一些网络教程上,经常看到RR级别是可以重复读的,但是无法解决幻读,只有串行化(Serializable)才能解决幻读,这个说法是否正确呢? 在这篇文章中,我将重点围绕MySQ...
  • 数据库的两种读,每种读读的数据版本不一样,所以也称为MVCC,即多版本并发控制a) 快照读select * from where xxx 这种形式的都是快照读。b) 当前读update , insert ,delete ,... 不可重复读幻读的区别:从总的结...
  • 作者:sanyuesan0000https://blog.csdn.net/sanyuesan0000事务隔离级别有四种,mysql默认使用的是可重复读,mysql是怎么实现可重复读的?为...
  • 透彻解读mysql的可重复读幻读及实现原理

    万次阅读 多人点赞 2019-05-15 15:21:30
    目录 一、事务的隔离级别 ...四、如何解决幻读 事务隔离级别有四种,mysql默认使用的是可重复读,mysql是怎么实现可重复读的?为什么会出现幻读?是否解决了幻读的问题? 一、事务的隔离级别 Re...
  • 并发场景下mysql会出现脏读、幻读、不可重复读问题; 脏读(dirty read): 某个事务正在修改数据但未提交,此时另一个事务去读取此条数据,后一个事务读取的不是最新的数据,是错误的。 解决办法:读取时加排它锁...
  • 1、数据脏读 事务a修改了某条数据,然后事务b...2、数据幻读 事务a按一定条件读取了该表的一些数据,然后事务b想该表插入了一些满足事务a查询条件的数据,当事务a再次以相同条件查询数据时,会发现多出来一些数据...
  • 事务的ACID属性原子性(Atomictiy)原子性是指事务是一个不分割的单位,事务中的操作要么都发生,要么都不发生。简单的来说就是在事务操作中,比如我通过两条SQL 改两条数据,要么这两个操作都完成,要么都不完成就...
  • 解决办法 解决脏读 @Transactional(isolation = Isolation.READ_COMMITTED)//读已提交 脏读 要求Transaction01只能读取Transaction...解决幻读 @Transactional(isolation = Isolation.SERIALIZABLE)//事务隔离级别,串

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,699
精华内容 18,279
关键字:

可重复读能解决幻读吗