标题 | 简介 | 类型 | 公开时间 | ||||||||||
|
|||||||||||||
|
|||||||||||||
详情 | |||||||||||||
[SAFE-ID: JIWO-2025-2229] 作者: 如一 发表于: [2018-12-19] [2018-12-19]被用户:如一 修改过
本文共 [650] 位读者顶过
正文开始我先提一下,根据事务的隔离级别不同,会有三种情况发生。即脏读、不可重复读、幻读。这里我先不提这三种情况的定义,后面在讲隔离级别的时候会补上。 这里,大家记住一点,根据脏读、不可重复读、幻读定义来看(自己总结,官网没有),有如下包含关系:
那么,这张图怎么理解呢? 即,如果发生了脏读,那么不可重复读和幻读是一定发生的。因为拿脏读的现象,用不可重复读,幻读的定义也能解释的通。但是反过来,拿不可重复读的现象,用脏读的定义就不一定解释的通了! 假设有表tx_tb如下,pId为主键
读未提交即READ_UNCOMMITTED,其实这个从隔离名字就可以看出来,一个事务可以读到另一个事务未提交的数据!为了便于说明,我简单的画图说明!
如图所示,一个事务检索的数据被另一个未提交的事务给修改了。 其内容为
翻译过来就是
你会发现,我们的演示结果和官网对脏读的定义一致。根据我们最开始的推理,如果存在脏读,那么不可重复读和幻读一定是存在的。 读已提交即READ_COMMITTED,这个也能看的出来,一个事务能读到另一个事务已提交的数据!为了便于说明,我简单的画图说明!
如图所示,一个事务检索的数据只能被另一个已提交的事务修改。
其内容为
翻译过来就是
ps:作者注,这里的不同结果,指的是在行不变的情况下(专业点说,主键索引没变),但是主键索引指向的磁盘上的数据内容变了。如果主键索引变了,比如新增一条数据或者删除一条数据,就不是不可重复读。 显然,我们这个现象符合不可重复读的定义。下面,大家做一个思考:
可重复读
即REPEATABLE_READ。这里,我改变一下顺序,先上幻读的定义
翻译过来就是
好了,接下来上图,大家自己评定该现象是否符合幻读的定义
显然,该现象是符合幻读的定义的。同一事务的两次相同查询出现不同行。下面,大家做一个思考:
接下来说一下,为什么很多文章都产生误传,说是可重复读可以解决幻读问题!原因出自官网的一句话
原文内容如下
按照原本这句话的意思,应该是
结果估计,某个国内翻译人员翻着翻着变成了
然后大家继续你抄我,我抄你,结果你懂的! 显然,漏了"使用了next-key locks!"这个条件后,意思完全改变,我们在该隔离级别下执行语句 select * from tx_tb where pId >= 1; 是快照读,是不加任何锁的,根本不能解决幻读问题,除非你用 select * from tx_tb where pId >= 1 lock in share mode; 这样,你就用上了next-key locks,才能解决幻读问题! 串行读即SERIALIZABLE_READ。在该隔离级别下,所有的select语句后都自动加上lock in share mode。因此,在该隔离级别下,无论你如何进行查询,都会使用next-key locks。所有的select操作均为当前读!
OK,注意看上表红色部分!就是因为在该隔离级别下使用了next-key locks,innodb将pId=1这条索引记录,和(1,++∞)这个间隙锁住了。其他事务要在这个间隙上插数据,就会阻塞,从而防止幻读发生! 有的人会说,你这第二次查询的结果,也变了啊,明显和第一次查询结果不一样啊?对此,我只能说,请看清楚啊。这是被自己的事务改的,不是被其他事物修改的。这不算是幻读,也不是不可重复读。 总结上面罗里吧嗦一大堆,最后来一个表格做总结吧,你面试答这个表就行。上面的一切是为了这张表做准备!
|