当前位置: 首页 > 科技观察

InnodbRR隔离级别能否避免幻读

时间:2023-03-14 23:28:57 科技观察

背景这件事要追溯到我以前背八股文章的时候。想必大家在背八股文的时候,已经把事务隔离级别背的很流利了。一般来说,说到隔离级别,都会顺带提到mysql的innodb的RR隔离级别。由于其独特的实现方式,通常会有如下一些描述:一直记在心里,mysql的Innodb在RR隔离级别下是可以避免幻读的(我面试的时候也是这样回答的),但是直到一个一天群里有个同学提了一个问题,我第一反应是怎么定义幻读?其实对于这场争论,很多人的观点是什么是幻读?首先,幻读的通俗定义。对于同一个区间查询,插入和删除操作使得同一个区间查询返回不同的结果。在Innodb的RR隔离级别下,比如我们删除一个表(id>1且i<100),此时另一个事务插入了一条id=50的数据。如果插入成功,会导致我们的第一个事务产生幻觉,所以inndodb中使用了next-key锁算法,即加了一个gaplock来防止插入意向锁。接下来看一下MySQL官方定义的幻读:翻译过来其实就是:当同一个查询在不同的时间产生不同的集合时,就会出现所谓的幻读问题。例如,如果SELECT被执行两次,但第二次返回第一次没有返回的行,则该行是“幻像”行。这个定义和我们一开始的定义有什么区别吗?看起来差别不大,但仔细观察第一个定义限制了插入和删除。MYSQL的官方定义下,使用了两个查询,并没有定义另一个事务做了什么,两个查询之间发生了什么,所以出现了这样的情况:上面有两个事务,事务B为什么会发生你说这是幻读现象?因为根据MySQL的定义,两次查询返回的是不同的集合,事务B确实出现了幻读现象,为什么会出现这种情况呢?这主要是因为innodb下所有的读都是快照读。如果我们把这个数据锁在事务中,它就变成了当前读,这样我们就可以读到事务A数据的写了。这种情况在一些文献中也被称为:writeskewstylephantom。RR级如何解决幻读?其实我们详细分析了上面这种情况是怎么解决幻读的,依赖next-keylock,而我们的第二种情况虽然是在事务中,但是没有使用next-keylock。如果我们真的有很多幻读的需求,那我们直接在查询的时候加上select...forupdate和lock,这样就可以直接转到当前读,从而避免幻读的发生。上篇文章营养价值不高,主要用来纠正你的一些观念。有时千篇一律的作文,不加深思熟虑就盲目背诵,容易导致认知错误。最后总结一下,在RR隔离级别下,只要没有快照读和当前读的切换,幻读其实是可以保证的。