(1)回顾
    RC隔离级别,实际上就是事务运行期间,只要别的事务修改数据还提交了,就可以读取别的事务修改的数据,所以是会发生不可重复读,幻读问题的,
    ReadView机制,是基于undo log版本链条实现的一套读视图机制,意思是 事务生成一个ReadView,然后事务自己更新的数据,自己是可以读到的,或者生成ReadView之前提交的事务修改的值也是可以读到的。
    但是如果你生成的ReadView的时候,就已经活跃的数据,在生成ReadView之后修改了数据,接着提交了,此时是读不到的,或者生成ReadView以后再开启的事务修改了数据,还提交了此时也是读不到的。

    (2)如何基于ReadView机制实现RC隔离级别
    假设数据库有一行数据,是事务id=50的一个事务之前就插入的,现在有两个活跃事务,一个是事务A(id=60),一个是事务B(id=70),现在情况是事务B发起一次update操作,更新了这条数据,把这条数据的值修改为了值B,所以此时这条数据的trx_id会变为事务B的id=70,同时会生成一条undo log,由roll_pointer来指向。
    这个时候事务A发起一次查询操作,此时发起查询操作就会生成一个ReadView,此时ReadView里的min_trx_id=60,max_trx_id=71,creator_trx_id=60,事务A发起查询,发现当前这条数据的trx_id是70。也就是说,属于ReadView的事务id范围之间,说明它生成ReadView之前就有这个活跃事务,是这个事务修改了这条数据的值,但是此时事务B还没提交,所以ReadView的m_ids活跃事务列表里,是有[60,70]两个的,所以此时根据ReaView的机制,此时事务A是无法查询事务B修改的值B的。
    58.jpg
    接着顺着undo log版本链条往下查找,就会找到一个原始值,发现他的trx_id是50,小于当前ReadView里的min_trx_id,说明它生成ReadView之前,就有一个事务插入了这个值并且提交了,因此可以查到这个原始值。
    接着假设事务B此时提交了,提交了事务B不会活跃于数据库里,事务B提交了那么按照RC隔离级别,事务B一旦提交说明事务A下次再次查询,就可以读到事务B修改过的值了。

    1. **怎样让事务A能够读到提交的事务B修改过的值呢?**<br /> 事务A下次再发起查询,再次生成一个ReadView。此时再次生成的ReadView数据库内活跃的事务只有事务A了,因此min_trx_id60max_trx_id71,但是m_ids这个活跃事务列表里只会有60,事务Bid=70不会出现在m_ids活跃事务列表里。<br /> 此时事务A再次基于ReadView查询,会发现这条数据的trx_id=70,虽然在ReadViewmin_trx_idmax_trx_id范围之间,但是此时并不在m_ids列表里,说明事务B在生成本次ReadView之前就已经提交了,既然生成本次ReadView之前,事务B就已经提交,就说明这次查询就可以查询到事务B修改过的这个值了,此时事务A就能查到事务B。<br />![59.jpg](https://cdn.nlark.com/yuque/0/2021/jpeg/232825/1631001802681-812d8427-721d-49e3-a03b-00302a62b7ea.jpeg#clientId=u299b6caa-393a-4&from=ui&id=u12072260&margin=%5Bobject%20Object%5D&name=59.jpg&originHeight=502&originWidth=1246&originalType=binary&ratio=1&size=113559&status=done&style=stroke&taskId=ue6a48034-1641-4251-a51d-1100848a09c)

    (3)总结
    到次为止,RC隔离级别如何实现的,他的关键点在于每次查询都会生成新的ReadView,那么如果在这次查询之前,有事务修改了数据还提交了,这次查询生成的ReadView里,那个m_ids列表当然不包括这个已经提交事务的,既然不包含已经提交的事务,那么自然就可以读到修改过的值。
    实际上,基于undo log多版本链条以及ReadView机制实现的多事务并发执行的RC隔离级别,RR隔离级别,就是数据库的MVCC多版本并发控制机制。本质是协调数据库并发运行的时候,并发的读写同一批数据,此时应该如何协调互相的可见性。

    首先RC机制是可以避免 脏读和脏写的,此时有两个事务,事务A和事务B,事务B修改该条数据,但是事务没提交,事务A现在去修改或者去读取,此时事务B进行了回滚,那么事务A修改的数据和查询的就都不对了,那么如果使用 Read View机制是怎么做的?假设事务A的id为60,事务B的id是70,针对该条数据的事务id是从0开始递增的,那么在事务B修改数据的同时,事务A开启了Read View,并进行了快照,包括事务id列表,max_trx_id,min_trx_id 和 creator_trx_id,那么此时creator_trx_id是 60,max_trx_id是70,min_trx_id是60,此时数据修改完成但是事务B没提交,所以事务A查询发现值变成了70对应的事务B,最大的max_trx_id也是70,且在活跃列表中也存在,说明事务A在查询时,事务B也在操作,所以查询不到,所以只能顺着undo log版本链查上一个数据,当事务B提交成功后,那事务A怎么能查询到呢?其实事务提交后,活跃列表里就没有了70,此时事务A看活跃列表里没有了事务B的id 70,这时候就能查到了。
    60.jpg