写点什么

三分钟掌握 MySQL-MVCC 底层原理

作者:采菊东篱下
  • 2024-12-29
    湖南
  • 本文字数:1007 字

    阅读完需:约 3 分钟

MVCC 介绍

mvcc 是 mysql 为了解决脏读不可重复读等事务之间读写问题而诞生的;它替代了一些场景下的低效锁,在保证隔离性的基础上,提升了读取效率和并发性。

MVCC 实现

在 mysql 中 mvcc 是基于 mysql 的 undo log 和 readview 来实现的。

undo log

在 innodb 中,每一条 sql 通过执行器后,就会在回滚段 undolog segment 中申请一个 undo log 页,根据 sql 信息来构建对应的 undo log 内容,同时将其写入磁盘,以保证每次操作真正数据之前 undo log 是完整的,之后才会执行数据写入记录 redo log 等。

undo log 格式


上图可以看到,每条 undo log 日志中会包含旧 roll_pointer,这样就方便 mysql 查询到之前的历史数据记录,而想知道 mysql 如何应用好这些版本记录,还需要了解一下 innodb 引擎数据行的格式,在 innodb 引擎中默认的格式为DYNAMIC,它的结构如下:


可以看到在每一行中都有一个字段来记录回滚指针,而该回滚指针就会指向 undo log,如下图:


这样通过 roll_pointer 关联,就把 undo log 组成一个链了,回滚时只需要依次撤销即可。

read view

在进行数据查询时,mysql 会构造一个 read view,它会记录该数据版本链的一些统计值例:1.m_ids:当前活跃的事务集合(还未提交的事务)2.min_trx_id:集合中最小事务编号(版本链结尾的事务 id)3.max_trx_id:集合中最大事务编号 + 14.creator_trx_id:创建当前视图的事务编号

构建完 read view 后根据以下规则查询即可:

image.png

  1. 判断当前版本数据是否为当前事务创建(creator_trx_id = trx_id),意味着读取自己修改的数据,是可以直接访问的;

  2. 如果当前版本数据的事务编号小于最小活跃事务(min_trx_id > trx_id),意味着该版本已经提交可以直接访问;

  3. 如果当前版本数据大于最大事务编号,则意味着创建该版本数据时还有生成该事务,需要遍历 undo log,直到版本数据小于 max_trx_id 或者 trx_id 为空没有数据为止;

  4. 当前版本数据的事务编号在 min_trx_id 和 max_trx_id 之间,同时不在活跃事务列表中,意味着创建事务时该版本数据已经提交可以查询到,如果不是则继续遍历 undo log.

通过以上规则进行查询,就可以实现查询到的都是已经提交事务的数据,解决了脏读问题。在事务第一个查询时创建一个 Read View,后续查询都用这个 Read View 进行判断,这样每次查询结果都是一样的,这样就解决了不可重复读问题;在可重复读的隔离级别下就采用这种方式来解决不可重复读问题;如果事务每次查询都创建一个 Read View,这样就会有不可重复读问题,在读已提交的事务隔离级别下就是这种实现方法。

用户头像

还未添加个人签名 2023-02-14 加入

还未添加个人简介

评论

发布
暂无评论
三分钟掌握MySQL-MVCC底层原理_Java_采菊东篱下_InfoQ写作社区