1、什么是MVCC
mvcc多版本同时控制。
在mysql innodb中,mvcc主要以更好的方式处理读/写冲突,以便在存在读/写冲突的情况下,可以在没有电缆或块的情况下同时进行读取,从而提高数据库的并发性。
2、实现原理:
通过保存某个时间点的数据快照,实现mvcc。 这意味着,无论运行多长时间,所有东西看到的数据都是一致的。
3、mvcc会解决那些问题吗?
同时执行事务可能会导致以下问题:
脏读:读取其他事务未提交的数据。 不可重新读取:当一个事务读取数据时,另一个事务修改该数据并将其提交给事务,导致重新读取时出现数据不匹配。 一个事务读取某个范围内的数据,另一个事务添加该范围内的数据,然后重新读取时发生了两次结果不匹配。 mvcc可以解决脏读、不可重复读,使用快照读解决了部分幻读问题,但由于修改时使用的是当前读,存在幻读问题,幻读问题最终通过间隙锁解决
4、当前导线和快照导线
当前读取:当前读取操作包括共享锁、独占锁和对DML操作的独占锁。 当前读取的数据都是最新的,在读取数据时将其锁定,以防止其他人修改当前记录。
快照读取—快照读取中的数据可能不是最新的,而是早期版本的数据。
如何区分当前读取和快照读取
所有未锁定的简单选择都是快照读取; 与此相对应的是现在的读法,在select上加上共享锁,再加上排他锁。
5、mvcc底层实现要素
在此之前,您必须知道MVCC仅适用于两个隔离级别:可重复读(REPEATABLE READ )和读命令。
mvcc的实现原理是通过隐藏字段(创建时的版本号、回滚指针、删除版本号)、还原日志和读视图来实现的。
5.1、隐藏字段
在Innodb存储引擎中,如果存在聚簇索引,则每行记录将隐藏两个字段;如果没有聚簇索引,则具有6byte的隐藏主键。
创建版本号:创建记录事务ID
删除版本号:删除/更改记录的事务ID。 这里只需将字段标记为删除状态。
回滚指针:指向记录的上一个版本
5.2、还原日志
undo log是为了实现原子性而实现回滚操作,另一个作用是实现MVCC的多版本控制。
还原日志细分为两种:插入时发生的还原日志、更新和删除时发生的还原日志
Innodb中insert生成的还原日志将在提交事务后删除。 新插入的数据没有历史版本,因此不需要维护还原日志。
update和delete操作生成的undo log都是类型,在事务回滚时需要,在快照读取时也需要,并且需要维护多个版本信息。 只有在快照读取和事务回滚不涉及日志的情况下,purge线程才会批量删除相应的日志。
purge线程清理还原日志的历史版本,还清理del flag标记的记录。
还原日志在mvcc中的作用是还原日志保存版本链。 也就是说,上述回滚指针字段已连接。
当数据库执行select语句时,它会尝试一致地读视图。
read view是查询时未提交的所有事务ID的数组,该数组中的最小事务ID由min_ID组成,创建的最大事务ID由max_id组成。 必须将查询的数据结果与read-view进行比较以获得快照结果。
因此,还原日志在mvcc中的作用是根据保存的事务ID和一致性视图进行比较,以获得快照结果。
5.3、读视图
执行SQL语句查询将生成一致性视图或读视图。 read-view由执行查询时尚未提交的所有事务ID数组和已创建的最大事务ID组成。
将该数组中最小的事务ID称为min_ID,最大的事务ID称为max_id,将查询的数据结果与读视图进行比较以获得快照结果。
因此,产生了使用当前记录的trx_id与read-view进行比较的比较规则。 比较规则如下。
5.3.1、版本链比较规则
如果落入trx_idmin_id,则此版本由已提交的事务生成,并且由于事务已提交,因此将显示数据
如果跌落到trx_idmax_id,则意味着此版本将由将来开始的事务生成,并且不显示
如果min_id=trx_id=max_id
如果row的trx_id位于数组中,则表示此版本由尚未提交的事务生成,并且是不可见的。 但是,如果当前自己的事务可见,row的trx_id不在数组中,则表示它是已提交的事务生成的版本。 在这里,您可以看到,对于删除的数据,在以前的还原日志中介绍时,也有update和delelect这样的特殊情况。
删除数据会复制版本链上的最新数据
份,然后将trx_id修改为删除时的trx_id,同时在该记录的头信息中存在一个delete flag标记,将这个标记写上true,用来表示当前记录已经删除。在查询时按照版本链的规则查询到对应的记录,如果delete flag标记位为true,意味着数据已经被删除,则不返回数据。
小结
在同一个事务中进行查询,会沿用第一次查询语句生成的read-view(前提是隔离级别是在可重复读)
通过以上的四个案例,在版本链寻找过程中,可以总结出一个小技巧
技巧图
根据这个小技巧你可以很快的得知此版本是否可见。
如果当前的事务ID在绿色部分,是已经提交事务,则数据可见如果当前的事务ID在蓝色部分,会有俩种情况,如果当前事务ID在read-view数组内,是没有提交的事务不可见,如果不在数组内数据可见如果落在红色部分,则不考虑,对于未来的事情不去想即可。
总结
本文内容从浅到深,从什么是mvcc到mvcc的底层实现,一步一步地陈述了mvcc的实现原理。
本文简单总结
mvcc在不加锁的情况下解决了脏读、不可重复读和快照读下的幻读问题,一定不要认为幻读完全是mvcc解决的对当前读、快照读理解,简单点说加锁就是当前读,不加锁的就是快照读。mvcc实现的三大要素俩个隐式字段、回滚日志、read-view俩个隐式字段:DB_TRX_ID:记录创建这条记录最后一次修改该记录的事务ID,DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本undo log在更新数据时会产生版本链,是read-view获取数据的前提read-view当SQL执行查询语句时产生的,是由为提交的事务ID组成的数组和创建的最大事务ID组成的版本链规则看第五节的小结即可