欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

事务的四大隔离级别中的幻读问题

程序员文章站 2022-05-09 15:14:27
...

1. 什么是幻读?

大部分学习过数据库的人应该都了解幻读这个概念,我在这里帮大家复习下。以下都是以InnoDB存储引擎为例进行说明。数据库并发访问中,针对delete和insert操作可能出现幻读这种现象。假设数据库的隔离级别是RC( READ COMMITTED),而且其中存在下图所示的数据,表名为account:

事务的四大隔离级别中的幻读问题

如果session 1 中操作:

1.start transaction;  

2.select count(id) from account;

3.commit;

session2中操作:

1.start transaction; 

2.insert into accout values(6,'徐六',1200);

3.commit;

如果现在先后执行上述两个session中的1,随后执行session 2中的2和3,最后执行session 1中的2,最后的结果是6,这个结果是符合逻辑的,即在插入一行数据之后,读取所有的数据行数是5+1,但是大家不妨仔细想一想,在session 1是在session 2之前开启事务的,所以session 1中应该读取的结果是5而不是6,这是因为session 2改变了session 1本来的结果集,从而导致了session 1的结果增加一条行记录,我们称上述现象为“幻读”。

幻读:事务A读取其符合条件的若干行,但是其他事务B改变了事务A的结果集,导致在事务A的结果集的个数增加或者减少,这种现象就叫做幻读。

2.幻读的解决方案

将数据库的隔离级别变成SERIALIZABLE就可以避免幻读现象的发生,REPEATABLE READ在某些情况下也可以避免幻读。其中SERIALIZABLE是数据隔离级别中最高的隔离级别,顾名思义,串行化,即数据库已经不存在并发执行,事务间是以串行方式执行,这种隔离级别的安全级别极高,但是并发性低,数据库的效率较低,适用于安全级别要求较高,性能要求较低的场合,而REPEATABLE是Mysql InnoDB存储引擎的默认隔离级别,可以在特殊情况下避免幻读。上述论述留下了一个问题,这就是在InnoDB存储引擎的REPEATABLE READ(RR)级别下如何避免幻读,原理是什么?

(1)在RR级别下避免幻读的发生,如果是在A事务中使用快照读先读取数据,无论事务B是否提交,在事务A中再一次快照读,读取的都是上一次快照读的数据;(这个是由快照生成的时间决定,具有不稳定性);

(2)如果是使用当前读读取事务,则内部原理就是使用next-key锁机制。next-key锁有两种,其一是行锁,其二是gap锁。如果是走的是唯一键索引,则如果是where条件全部命中,则仅需要使用行锁(为什么?原因是如果全部命中而且还是唯一索引则另一个事务无法对该事务中where后面的范围中的数据再一次进行操作,因为是唯一的),反之,需要行锁+gap合力作用,锁住可能出现幻读的数据范围。如果走的是非唯一索引或者是不加索引,则需要是行锁+gap锁两种锁。

  • 下面详细分析下如果是非唯一索引的情况下加gap锁的细节:

                                               事务的四大隔离级别中的幻读问题

以上述例子为说明,如果事务A要删除id = 9的行,这个时候会在id = 9的行上加上Gap锁,其中在区间(6,9]和(9,11]的区间上加上Gap锁,这个区间在事务A提交之前是无法操作的。如果事务B对上述区间操作中的增加id=9的数据,是会出现幻读的。

由于B+树的叶子节点的数据是按照顺序进行存放的,所以对于边界条件上的情况分辨如下:

可能出现幻读的区域为:{id,name}:({6,c}--{9,b}] ({9,b}--{9,d}] ({9,d}--{11,f}]

故而:{6,b}不会加锁,{6,dd}加锁,无法插入 {6,c}<{6,xx}都是会被加上Gap锁

同理:{11,g}不会被加锁,{11,f}会被加上锁,{11,yy}<={11,f}都是会被加上Gap锁

  • 如果不加索引的情况下加gap锁的细节:

                                              事务的四大隔离级别中的幻读问题

当前读操作如果不使用索引,则所有的区间都会被Gap锁锁住,类似于锁表,这种情况需要避免,因为这样数据库的效率很低。

综上所述,在RR级别下使用当前读操作可以避免出现幻读,快照读操作是可能无法彻底避免幻读的产生,这个和快照生成的时机有着关系。