简单理解版下面先引用我之前写的文章中的内容,可以快速理解。建议先简单看一下。要说幻读,首先要了解MVCC。MVCC全称为多版本并发控制。其实就是保存了某个时间节点的数据快照。我们实际上为每行数据隐藏了两列,创建时间版本号和过期(删除)时间版本号。每次启动新事务时,版本号都会自动递增。还是以上面的user表为例,假设我们插入两条数据,其实应该是这样的。此时假设小明执行查询。此时current_version=3select*fromuserwhereid<=3;同时小红此时启动一个事务修改id=1的记录,current_version=4updateusersetname='张三三'whereid=1;执行成功后的结果是这样的。如果此时小黑还在删除id=2的数据,current_version=5,执行后的结果是这样的。由于MVCC的原理是发现创建版本小于等于当前事务版本,删除版本为null或者大于当前事务版本,所以小明真正的查询应该是select*fromuserwhereid<=3andcreate_version<=3and(delete_version>3ordelete_versionisnull);所以小明最后id=1的名字还是'张三',id=2的记录也可以查询到。这样做是为了确保事务读取的数据在事务开始之前就已经存在,或者是事务本身插入或修改的。真正的原理其实上面的说法只是一个简化版的理解。真正的MVCC是用来控制读提交和可重复读级别的,主要是通过undolog日志版本链和读视图。每条数据的两个隐藏字段不是创建时间版本号和过期(删除)时间版本号,而是roll_pointer和trx_id。roll_pointer指向事务更新前产生的undolog,undolog用于事务回滚,保证事务的原子性。trx_id是最近一次数据更新的交易ID。以上面的例子为例,一开始插入了两条数据。真实情况是这样的,因为第一次数据插入没有undolog,所以roll_pointer指向一个空的undolog。这时候假设小明执行查询,会打开一个readview,readview里面包含几个重要的东西。m_ids是尚未提交的事务id的low_limit_id集合,m_ids中的最小值up_limit_id,m_ids中的最大值creator_trx_id,创建读视图的事务ID,也就是自己执行查询的事务ID小明,当前交易ID=3select*fromuserwhereid<=3;小红此时启动一个事务修改id=1的记录,事务ID=4updateusersetname='张三三'whereid=1;这是小明此时的阅读视图。m_ids=[3,4]low_limit_id=3up_limit_id=5creator_trx_id=3所以小明在执行查询的时候会判断当前数据的trx_id。这时候小红的修改也完成了,小红的数据就变成了这样。如果小明再去查看,会发现readview当前的trx_id>low_limit_id,即4>3,不符合条件。同时他发现当前trx_id=4在low_limit_id和up_limit_id[3,5]之间,trx_id=4在m_ids=[3,4]之间,所以会根据指向的undolog查找通过roll_pointer,trx_id=1小于当前的low_limit_id=3,如果满足条件,就会找到上一版本name=张三的记录。如果此时小明修改这条记录的值,把名字改成张武,结果就是这样的。那么如果小明去查询,会发现当前的trx_id=3是自己的creator_trx_id,也就是他自己,所以直接返回这个数据。因此,我们可以先总结出以下几种情况:如果trx_id是第一次开启交易查询<>如果trx_id>low_limit,trx_id还在[low_limit_id,up_limit_id]范围内,trx_id在m_ids中,会根据到roll_pointerundolog日志链,找到之前版本的数据,对应小红修改后小明再次查询的场景。如果trx_id=creator_trx_id,那么说明是自己修改的,直接返回即可,对应小明自己修改数据场景中不同隔离级别的实现根据上面解释的原理,你可能已经发现了这个就是实现了可重复读,保证了每次读取的数据都是一致的。那么,如果是readsubmitted级别,这个是怎么实现的呢?其实很简单。在上面的原理讲解中,我一直假设每次查询都会生成读视图,后面不会重新生成。在读取提交级别下,为每个查询生成一个读取视图。以上面小红改造张三后的场景为例。在可重复性层面,由于trx_id>low_limit,trx_id还在[low_limit_id,up_limit_id]范围内,trx_id在m_ids中,满足我们上面的条件2,所以会根据roll_pointer找到之前的版本记录,保证反复阅读。在读取提交级别,重新生成读取视图。此时trx_id不在m_ids中,说明交易已经提交,所以可以直接返回这个数据,所以查到的数据是小红修改后的名字=张三的三个数据。本文转载自微信公众号“爱小仙”,可通过以下二维码关注。转载本文请联系艾小仙公众号。
