mvcc机制是基于mysql在读已提交和可重复读隔离级别下的。在默认的可重复读的事务隔离级别下,它能保证某一事物在多次查询同一个sql时查询结果都相同,可以有效的隔离其他事务修改提交的数据,通过多版本并发控制能保证一定的并发,避免加锁控制。而串行化事务隔离级别下是通过加锁控制的,效率低下。
undo日志版本链和read-view机制
MVCC机制是靠undo日志版本链和read-view机制实现的。undo日志版本链是指一行数据被多个事务修改后生成的一组日志版本链路,每条日志会记录事务trx_id和指向上一条日志的指针roll_pointer。如图:
在可重复读隔离级别下,开启一个事务,并执行任何查询sql时会生成当前事务一个固定的read view(如果是读已提交事务隔离级别每次执行查询sql时都会重新生成),read view是由所有尚未提交的事务id和此时最大的事务id组成的。例如,read view:[199,200],200,表示事务id为198的事务已经提交,199和200是没有提交的事务,200以上则是尚未开始的事务。
在可重复读事务隔离级别下,假设198已经提交,此时开启事务A和事务B,事务A先执行查询sql就会生成read view:[199,200],200,查询结果name为rick33;此时事务id为199的事务修改name为rick11并提交,事务A再次执行相同的查询sql,查询name依旧为rick33,因为事务A生成的read view不变,事务A还是认为只有事务198是已经提交的,所以查询的结果不变;事务B此时执行查询sql并生成read view:[200],200,事务B能感知到199事务已经提交,查询结果name为rick11。
对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。
1、加载需要更新的数据所在页到Buffer Pool中
2、将需要更新的原始数据写入到redo日志
3、将server组件需要修改的数据更新到Buffer Pool中覆盖原始数据
4、并将修改的数据写入到Redo log Buffer
5、准备提交事务,将Redo Log Buffer中的数据写入到Redo Log磁盘文件
6、准备提交事务,通过server组件将需要更新的数据写入到binlog文件中
7、写入commit标记到redo日志中,该标志表示提交事务完成保证binlog和redo log文件数据一致
8、InnoDB内置IO线程随机(没有规定时间)将Buffer Pool中数据以页的方式写入到InnoDB表中
undo日志和read view是可以保证读写和写读能并发执行提高性能,还有如果事务提交失败需要回滚也需要undo日志。redo日志是保证如果Buffer Pool中数据没有及时写入到磁盘mysql宕机了,在mysql重启时可以恢复数据,是因为数据写入redo日志是顺序写的,速度是写入表的几倍(数据写入表是随机的,表数据会删除),几乎可以媲美数据写入内存。binlog日志是保证数据库被删除后,可以恢复大部分数据。