精华内容
下载资源
问答
  • //MySQL如何解决幻读问题?// 先来说说幻读的概念吧,在MySQL中,如果一个事务A根据某种特定条件的SQL查询出来一些记录record_a,此时另外一个事务插入了一些符合这种特定条件的记录record_b,原先的事务再次根据...

    ada6a34b21191d7c4a1f3a85d32fae76.png

    527ae571f2679f02a350be284c4623bf.gif//MySQL如何解决幻读问题?//

        先来说说幻读的概念吧,在MySQL中,如果一个事务A根据某种特定条件的SQL查询出来一些记录record_a,此时另外一个事务插入了一些符合这种特定条件的记录record_b,原先的事务再次根据同样的SQL,查询到了record_a和record_b,这种现象就称之为幻读。

        注意,下面两种情况不能称之为幻读:

    1、如果查出来数据比record_a的记录要少,

    2、或者查出来的数据跟record_a记录一样,但是记录发生了变化。

        幻读强调的是一个事务按照相同的SQL查询了记录之后,后续的结果中出现了之前结果中不存在的值。

    在默认RR隔离级别下,当发生了幻读现象之后,MySQL解决这种情况会使用两种方案。

    方案一:读操作利用MVCC解决,写操作利用加锁解决

    MVCC知识可以查看之前的文章:

    《MySQL之MVCC初探(1)

    MVCC其实是借助于Readview(读视图)的概念,对数据库生成Readview时刻的版本做了一个快照。普通的查询语句只能看到生成Readview之前已经提交的事务,在生成Readview之前未提交的事务或者生成Readview之后才开启的事务是看不到的。MVCC情况下读取的都是记录的历史版本,而写操作都是更新的是记录的最新版本,因此,MVCC情况下,读操作和写操作本身并不冲突。

    说的更简单一点就是RR隔离级别下,事务在第一次select的时候只生成一次Readview(类似拍了一张照片),后续的查询都复用这个Readview(同样的照片),当然,也就不会出现幻读现象了。

    方案二:读写操作都采用加锁的方式

    在银行支付等场景下,不允许读取记录的历史版本,只允许看到记录的最新版本,此时读操作和写操作都需要加锁,其实,要解决幻读问题,只添加记录锁于事无补,因为幻读的记录在第一次读取之前是不存在的,即使你给记录上了记录锁,但是不存在的记录上面如果没有锁,还是会造成幻读。

    为了解决这个问题,MySQL引入了间隙锁,间隙锁的引入,阻止了其他会话在指定的间隙插入相关记录,也就解决了幻读的问题。

    两种方案对比:

    如果采用MVCC方式的话,只能解决一致性非锁定读(也称之为快照读)的幻读问题,读-写操作彼此并不冲突,并发性能更高;

    如果采用加锁方式的话,可以解决当前读的幻读情况,读-写操作彼此需要排队执行,影响性能;

    一般情况下我们当然愿意采用MVCC来解决读-写操作并发执行的问题,但在银行业务等特殊场景下,还是需要锁来解决的。

    a8bc52f702e7165af5ce597310e0d7f7.png828c0f18cb6f9e843d6219a22cfdc62f.png有帮助的话还希望点下再看哈
    展开全文
  • 幻读也是在面试中经常被问到的,今天我们按照下面几个方面讲解幻读是什么幻读有什么问题如何解决幻读首先我们建立我们的表,且插入6条数据,如下图CREATE TABLE `t` (`id` int(11) NOT NULL,`c` int(11) DEFAULT ...
    幻读也是在面试中经常被问到的,今天我们按照下面几个方面讲解
    1. 幻读是什么

    2. 幻读有什么问题

    3. 如何解决幻读

    首先我们建立我们的表,且插入6条数据,如下图
    CREATE TABLE `t` (`id` int(11) NOT NULL,`c` int(11) DEFAULT NULL,`d` int(11) DEFAULT NULL,  PRIMARY KEY (`id`),KEY `c` (`c`)) ENGINE=InnoDB;insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);

    幻读是什么

    按照上面建表语句,我们做如下操作

    98cda0961589e691a10c938c62592b8f.png

    sessionA中添加了三条相同的语句,都是给d=5这行添加行锁,且使用当前读,而上面运行的结果如下
    1. Q1仅仅返回id=5这一行

    2. 由于sessionB修改了id=0中的d=5,在Q2中返回id=0,5

    3. sessionC插入id=1这行数据,Q3返回id=0,1,5

    这里Q3读到id=1这行数据就是幻读,幻读是指在一次事务中,前后两次相同的范围查询,看到了不一样的数据。
    •  在可重复读级别下,普通查询是读取快照读,不可以看到其他事物中的插入的数据,只有当前读,才会有幻读

    • 上面的Q2不是幻读,他是当前读,幻读是针对新插入行

    幻读有什么问题

    • 破坏语义

    sessionA中T1select *  from 他where d=5 for update 这句就是在锁住d=5所有行,不准别的事物进行读写操作,但是按照下面执行就会破坏

         983febc8813157e12d97f7feeca3ef64.png      sessionB中的语句是对id=0的记录进行了修改d=5.c=5(0,5,5),由于sessionA只对id=5进行了加行锁,所以sessonB的两条更新语句没有问题,但是也就是破坏了d=5行的记录加锁的声明。

    • 一致性问题

    数据的一致性不仅仅是数据此刻的一致性,也包括数据和日志上的逻辑一致性,如我们在sessionA上加上下面语句.
    update t set d=100 where d=5。

    64c71da52e6ba63ead1a5f0020dc07b7.png

            上面执行完之后会是上面结果呢
      1. 经过T1执行结果是(5,5,100)

      2. 经过T2执行结果是(0,5,5)

      3. 经过T4执行结果是(1,5,5)     

    上面数据上没有说明问题,我们再看看日志的记录
    1. T2时刻事物B提交了两条更新语句

    2. T4时刻事物C提交了两条语句

    3. T6时刻事物A提交了一个语句update t set d=100 where id=5

    按照上面事物提交的序列日志如下记录
    update t set d=5 where id=0; /*(0,0,5)*/update t set c=5 where id=0; /*(0,5,5)*/insert into t values(1,1,5); /*(1,1,5)*/update t set c=5 where id=1; /*(1,5,5)*/update t set d=100 where d=5;/*所有d=5的行,d改成100*/
    看到日志,我们发现日志不管在哪里进行执行,最终的记过是(0,5,100)(1,5,100)(5,5,100),数据发生了不一致.我们发现原来是此时只对id=5这一行进行了加锁,如果是对扫描的所有行加锁,是不是就可以了.看看下面执行的结果

    2158aa84f54d04377f095a2f9829ac45.png

    在sessionA还没有提交的时候,是对所有行进行了加做,sessionB此刻是阻塞的,id=0执行的结果是(0.5,5),我们在看看日志的如何记录
    insert into t values(1,1,5); /*(1,1,5)*/update t set c=5 where id=1; /*(1,5,5)*/update t set d=100 where d=5;/*所有d=5的行,d改成100*/update t set d=5 where id=0; /*(0,0,5)*/update t set c=5 where id=0; /*(0,5,5)*/
    按照上面执行日志的记录,最终的id=0的结果是(0,5,5),但是我们发现id=1的结果却是(1,5,100),原因很简单,在T3时刻给所有记录加了锁,但是id=1此时不存在,因此没有加上锁,所以即使对所有的记录加上锁,也不能给新增的记录加上锁。最终也会导致数据不一致的问题。

    如何解决幻读

    我们知道行锁只能锁住行,但是新插入的记录是更新记录的间隙,因此引入了间隙锁,顾名思义就是两条记录的间隙,正如文章开头的记录,插入6条记录就有7个间隙                                                 e179d09cc2abe732dedfbd4169e55390.png

    这 样不仅仅对每一行数据加上了行锁,也为每一个间隙加上了间隙锁,因此新增的数据就无法插入。

    行锁和行锁之间是有冲突的,但是间隙锁和间隙锁是没有冲突的,间隙做的冲突是往这个间隙插入记录的操作存在冲突,

    eca4ed04e172e45dc80139f0212c9b6d.png

    我们看到对于不存在的记录,sessionA和sessionB都会给(0,5]这个间隙加上间隙锁,目的是一样的不允许插入值。间隙锁和行锁合起来就是next-key lock,每个next-key lock是前开后闭的,如果使用select *  from t for update ,就是对表的所有记录加锁,就形成了7个next-key lock,分别是 (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。

    next-lock key 的引入虽然解决了幻读的问题,但是也引来了一些问题

    如下图执行结果,就可能引起死锁

    e9a1d322384610eea047cb4cdbd9f58a.png

    执行顺序
    1. sessionA先查询id=9不存在,就加上间隙锁(5,10]

    2. sessionB同理也会加上间隙锁(5,10]

    3. sessionB执行插入id=9的记录阻塞,等待sessionA释放间隙锁

    4. sessionA同理也被锁住,阻塞中,等待sessionB释放间隙锁

    因此引入的间隙锁会增加锁的范围,影响并发度,那么我们还有其他办法解决幻读的问题吗,答案是有的,Mysql默认的事物隔离级别是可重复读,但是如何我们把事物设置成读已提交和binlog_format=row,也是可以解决幻读的问题,当然要这样配置是否合理要看你们的业务场景.

    果对您有一丝丝帮助,麻烦点个关注,也欢迎转发,谢谢

    扫码关注417d6a87920d023d5cb69bdf10bd3b52.png
    展开全文
  • MySQL 是如何解决幻读的一、什么是幻读在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。而多出来或者少的哪一行被叫做 幻行二、为什么要解决幻读在高并发数据库系统中,需要保证事务与事务之间的...

    MySQL 是如何解决幻读的

    一、什么是幻读

    在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。

    而多出来或者少的哪一行被叫做 幻行

    二、为什么要解决幻读

    在高并发数据库系统中,需要保证事务与事务之间的隔离性,还有事务本身的一致性。

    三、MySQL 是如何解决幻读的

    如果你看到了这篇文章,那么我会默认你了解了 脏读 、不可重复读与可重复读。

    1. 多版本并发控制(MVCC)(快照读)

    多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的。

    以 InnoDB 为例,每一行中都冗余了两个字断。一个是行的创建版本,一个是行的删除(过期)版本。版本号随着每次事务的开启自增。事务每次取数据的时候都会取创建版本小于当前事务版本的数据,以及过期版本大于当前版本的数据。

    普通的 select 就是快照读。

    select * from T where number = 1;

    原理:将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的。

    2. next-key 锁 (当前读)

    next-key 锁包含两部分

    记录锁(行锁)

    间隙锁

    记录锁是加在索引上的锁,间隙锁是加在索引之间的。(思考:如果列上没有索引会发生什么?)

    select * from T where number = 1 for update;

    select * from T where number = 1 lock in share mode;

    insert

    update

    delete

    原理:将当前数据行与上一条数据和下一条数据之间的间隙锁定,保证此范围内读取的数据是一致的。

    其他:MySQL InnoDB 引擎 RR 隔离级别是否解决了幻读

    引用一个 github 上面的评论 地址:

    Mysql官方给出的幻读解释是:只要在一个事务中,第二次select多出了row就算幻读。

    a事务先select,b事务insert确实会加一个gap锁,但是如果b事务commit,这个gap锁就会释放(释放后a事务可以随意dml操作),a事务再select出来的结果在MVCC下还和第一次select一样,接着a事务不加条件地update,这个update会作用在所有行上(包括b事务新加的),a事务再次select就会出现b事务中的新行,并且这个新行已经被update修改了,实测在RR级别下确实如此。

    如果这样理解的话,Mysql的RR级别确实防不住幻读

    有道友回复 地址:

    在快照读读情况下,mysql通过mvcc来避免幻读。

    在当前读读情况下,mysql通过next-key来避免幻读。

    select * from t where a=1;属于快照读

    select * from t where a=1 lock in share mode;属于当前读

    不能把快照读和当前读得到的结果不一样这种情况认为是幻读,这是两种不同的使用。所以我认为mysql的rr级别是解决了幻读的。

    先说结论,MySQL 存储引擎 InnoDB 隔离级别 RR 解决了幻读问题。

    如引用一问题所说,T1 select 之后 update,会将 T2 中 insert 的数据一起更新,那么认为多出来一行,所以防不住幻读。看着说法无懈可击,但是其实是错误的,InnoDB 中设置了 快照读 和 当前读 两种模式,如果只有快照读,那么自然没有幻读问题,但是如果将语句提升到当前读,那么 T1 在 select 的时候需要用如下语法: select * from t for update (lock in share mode) 进入当前读,那么自然没有 T2 可以插入数据这一回事儿了。

    注意

    next-key 固然很好的解决了幻读问题,但是还是遵循一般的定律,隔离级别越高,并发越低。

    展开全文
  • 一、什么是幻读在一次事务里面,多次...三、MySQL 是如何解决幻读的如果你看到了这篇文章,那么我会默认你了解了 脏读 、不可重复读与可重复读。1. 多版本并发控制(MVCC)(快照读/一致性读)多数数据库都实现了多版本...

    一、什么是幻读

    在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。而多出来或者少的哪一行被叫做 幻行

    二、为什么要解决幻读

    在高并发数据库系统中,需要保证事务与事务之间的隔离性,还有事务本身的一致性。

    三、MySQL 是如何解决幻读的

    如果你看到了这篇文章,那么我会默认你了解了 脏读 、不可重复读与可重复读。

    1. 多版本并发控制(MVCC)(快照读/一致性读)

    多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的。以 InnoDB 为例,每一行中都冗余了两个字断。一个是行的创建版本,一个是行的删除(过期)版本。具体的版本号(trx_id)存在 information_schema.INNODB_TRX 表中。版本号(trx_id)随着每次事务的开启自增。

    事务每次取数据的时候都会取创建版本小于当前事务版本的数据,以及过期版本大于当前版本的数据。

    普通的 select 就是快照读。

    select * from T where number = 1;

    原理:将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的。

    2. next-key 锁 (当前读)

    next-key 锁包含两部分

    • 记录锁(行锁)

    • 间隙锁

    记录锁是加在索引上的锁,间隙锁是加在索引之间的。(思考:如果列上没有索引会发生什么?)

    select * from T where number = 1 for update;

    select * from T where number = 1 lock in share mode;

    insert

    update

    delete

    原理:将当前数据行与上一条数据和下一条数据之间的间隙锁定,保证此范围内读取的数据是一致的。

    其他:MySQL InnoDB 引擎 RR 隔离级别是否解决了幻读

    引用一个 github 上面的评论 地址:

    Mysql官方给出的幻读解释是:只要在一个事务中,第二次select多出了row就算幻读。
    a事务先select,b事务insert确实会加一个gap锁,但是如果b事务commit,这个gap锁就会释放(释放后a事务可以随意dml操作),a事务再select出来的结果在MVCC下还和第一次select一样,接着a事务不加条件地update,这个update会作用在所有行上(包括b事务新加的),a事务再次select就会出现b事务中的新行,并且这个新行已经被update修改了,实测在RR级别下确实如此。

    如果这样理解的话,Mysql的RR级别确实防不住幻读

    有道友回复 地址:

    在快照读读情况下,mysql通过mvcc来避免幻读。
    在当前读读情况下,mysql通过next-key来避免幻读。
    select * from t where a=1;属于快照读
    select * from t where a=1 lock in share mode;属于当前读

    不能把快照读和当前读得到的结果不一样这种情况认为是幻读,这是两种不同的使用。所以我认为mysql的rr级别是解决了幻读的。

    先说结论,MySQL 存储引擎 InnoDB 隔离级别 RR 解决了幻读问题。

    如引用一问题所说,T1 select 之后 update,会将 T2 中 insert 的数据一起更新,那么认为多出来一行,所以防不住幻读。看着说法无懈可击,但是其实是错误的,InnoDB 中设置了 快照读 和 当前读 两种模式,如果只有快照读,那么自然没有幻读问题,但是如果将语句提升到当前读,那么 T1 在 select 的时候需要用如下语法: select * from t for update (lock in share mode) 进入当前读,那么自然没有 T2 可以插入数据这一回事儿了。

    注意

    1. next-key 固然很好的解决了幻读问题,但是还是遵循一般的定律,隔离级别越高,并发越低。

    LastSun

    https://www.cnblogs.com/wdy1184/p/10655180.html

    2d70c59ae78e8f9d2b27175ca8eae312.png

    展开全文
  • 三、MySQL 是如何解决幻读的 1. 多版本并发控制(MVCC)(快照读) 多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的。 以 InnoDB 为例,每一行中都冗余了两个字段。一个是行的创
  • Mysql如何解决幻读

    2020-01-07 01:07:42
    Mysql如何解决幻读? Mysql日常开发中接触到最多的事务隔离级别分别是READ-COMMITTED和REPEATABLE-READ也就是我们常说的提交读和可重复读。Innodb的RR级别和RC级别最大的区别就是增加了间隙锁,但间隙锁是如何解决...
  • 三、MySQL 是如何解决幻读的 如果你看到了这篇文章,那么我会默认你了解了 脏读 、不可重复读与可重复读。 1. 多版本并发控制(MVCC)(快照读) 多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的...
  • 准备众所周知,数据库事务有以下四种隔离级别,其中mysql默认隔离级别是RR,但是mysql的innodb引擎一定程度可以避免幻读。事务隔离级别脏读不可重复读幻读读未提交(read-uncommitted)是是是不可重复读(read-...
  • MySql是如何解决幻读的?

    万次阅读 热门讨论 2019-05-31 20:36:44
    MySql是如何解决幻读的? 一,前言: 事务的隔离级别有四种,读未提交,读已提交,可重复读和串行化,下面结合具体的问题,在mysql中,innodb引擎是怎么解决幻读的? 二,详情: 一张图胜过千言万语: ...
  • MySQL 是如何解决幻读的如果你看到了这篇文章,那么我会默认你了解了 脏读 、不可重复读与可重复读。1. 多版本并发控制(MVCC)(快照读/一致性读)多数数据库都实现了多版本并发控制,并且都是靠保存数...
  • 一、什么是幻读在一次事务里面,...三、MySQL 是如何解决幻读的如果你看到了这篇文章,那么我会默认你了解了脏读、不可重复读与可重复读。1. 多版本并发控制(MVCC)(快照读/一致性读)多数数据库都实现了多版本并发控...
  • 在MYSQL的RR隔离级别下, MYSQL也解决了幻读的问题。...MVCC如何解决幻读beginselect count(*) from table where id >10...... 一系列的其他操作 ......select count(*) from table where id >10comm...
  • InnoDB默认的隔离级别是RR(可重复读),可以解决脏读和不可重复读,但是不能解决幻读问题。什么是幻读?事务A读取了一个范围内的数据,此时事务B在该范围内插入了一条数据,并立马提交了事务,此时事务A再次读取这个...
  • 一、什么是幻读在一次事务里面,...三、MySQL 是如何解决幻读的1. 多版本并发控制(MVCC)(快照读)多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的。以 InnoDB 为例,每一行中都冗余了两个字断。一...
  • 一、什么是幻读在一次事务...三、MySQL 是如何解决幻读的如果你看到了这篇文章,那么我会默认你了解了 脏读 、不可重复读与可重复读。1. 多版本并发控制(MVCC)(快照读)多数数据库都实现了多版本并发控制,并且都是靠...
  • 一、什么是幻读 在一次事务里面,多次查询之后,查询的结果集的个数不一致的...三、MySQL 是如何解决幻读的 如果你看到了这篇文章,那么我会默认你了解了脏读、不可重复读与可重复读。 1. 多版本并发控制(M...
  • MySQL 是如何解决幻读的一、什么是幻读在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。 而多出来或者少的哪一行被叫做 幻行 二、为什么要解决幻读在高并发数据库系统中,需要保证事务与事务之间...
  • MySQL 是如何解决幻读的一、什么是幻读在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。 而多出来或者少的哪一行被叫做 幻行 二、为什么要解决幻读在高并发数据库系统中,需要保证事务与事务之间...
  • 作者:何新生-功夫熊猫原文:https://blog.csdn.net/u013067756/article/details/90722490一,前言事务的隔离级别有四种,读未提交,读已提交,可重复读和串行化,...2, 为什么要解决幻读?3, mysql是怎么解决幻读的?3.1...
  • 一,前言:事务的隔离级别有四种,读未提交,读已提交,可重复读和串行化,下面结合具体的问题,在mysql中,innodb引擎是怎么解决幻读的?二,详情:一张图胜过千言万语:1, 什么是幻读?2, 为什么要解决幻读?3, mysql是怎么解决...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 328
精华内容 131
关键字:

如何解决幻读