当前读和快照读

3,198 阅读3分钟

前言:

    这两个知识点折磨了自己蛮久,终于搞懂了。学东西,第一遍很容易迷糊,需要看第二遍,还迷糊的话 再总结一番,基本不会有太大问题~

1.这个答案的前情:

        innoDB的默认隔离级别可重复读,利用MVCC实现,但是MVCC并不能真正解决幻读,可以通过实验知道,事务A开启之后,select,然后事务B进来,插入一条数据,此时A去修改那条数据,是可以修改的! 出现幻读

一旦某个事物在事务中的修改操作覆盖到了其他事务插入的“幻行”,那么这些“幻行”在下次查询时就会再次出现,从而出现幻象问题。

(详情见 牛客网上那篇有名的帖子~~)

2.某大佬的回答:

我的理解是,问题出在了update语句执行时,此时会先执行--当前读,并加写锁,快照读会按照事务id来选择可见的数据,但是当前读不管这些,直接获取最新的数据,能够读到,就能修改,修改完行数据对应的事务id更新,再去快照读,自然出现了幻读;所以应该可以理解为为了保证当前读的强一致性而导致的漏洞,不知道这样分析有没有问题。。。

3.摘录于某博客(后面会贴出链接):

1、select快照读(照片)

  当你执行select *之后,在A与B事务中都会返回4条一样的数据,这是不用想的,当执行select的时候,innodb默认会执行快照读,相当于就是给你目前的状态找了一张照片,以后执行select 的时候就会返回当前照片里面的数据,当其他事务提交了也对你不造成影响,和你没关系,这就实现了可重复读了,那这个照片是什么时候生成的呢?不是开启事务的时候,是当你第一次执行select的时候,也就是说,当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据......之后无论再有其他事务commit都没有关系,因为照片已经生成了,而且不会再生成了,以后都会参考这张照片。

2、update、insert、delete 当前读

  当你执行这几个操作的时候默认会执行当前读,也就是会读取最新的记录,也就是别的事务提交的数据你也可以看到,这样很好理解啊,假设你要update一个记录,另一个事务已经delete这条数据并且commit了,这样不是会产生冲突吗,所以你update的时候肯定要知道最新的信息啊。

  我在这里介绍一下update的过程吧,首先会执行当前读,然后把返回的数据加锁,之后执行update。加锁是防止别的事务在这个时候对这条记录做什么,默认加的是排他锁,也就是你读都不可以,这样就可以保证数据不会出错了。但注意一点,就算你这里加了写锁,别的事务也还是能访问的,是不是很奇怪?数据库采取了一致性非锁定读,别的事务会去读取一个快照数据。   innodb默认隔离级别是RR, 是通过MVVC来实现了,读方式有两种,执行select的时候是快照读,其余是当前读,所以,mvvc不能根本上解决幻读的情况

参考:www.jianshu.com/p/27352449b…