mvcc多版本并发控制原理

116 阅读4分钟

基本概念:

多版本并发控制(MVCC) 是通过保存数据在某个时间点的快照来实现并发控制的。 也就是说,不管事务执行多长时间,事务内部看到的数据是不受其它事务影响的,根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。

版本链

InnoDB存储引擎的表,每一行记录中都包含一些隐藏字段,其中下面两个字段对MySQL实现MVCC起到重要作用:

  • db_trx_id:最后操作(插入或更新)这条记录的事务 ID。每次一个事务对某条记录进行改动时,都会把该事务的 ID赋值给 db_trx_id 隐藏字段。
  • db_roll_ptr回滚指针,也就是指向这个记录的 undo 日志 信息。每次一个事务对某条引记录进行改动时,都会把旧的版本记录写入到 undo 日志 中,然后 db_roll_ptr 就相当于一个指针,可以通过它来找到该记录修改前的信息。

image.png undo 日志 又叫做 回滚日志,它可以保存事务发生期间的数据版本,可以用于回滚,同时可以提供多版本并发控制(MVCC)下的读操作

读视图

Read View是一个数据库的内部快照,该快照被用于InnoDB存储引擎中的MVCC机制。简单点说,Read View就是一个快照,保存着数据库某个时刻的数据信息。在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)。

这个ReadView中主要包含4个比较重要的内容,分别如下:

creator_trx_id ,创建这个Read View 的事务ID,即创建者的事务ID,而不是记录中的trx_id!

说明:只有在对表中的记录做改动时(执行INSERTDELETEUPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都 默认为0

m_ids :表示创建ReadView时当前系统中活跃的事务的ID集合 (“活跃"指的就是,启动了但还没提交)。

min_trx_id :表示创建ReadView时活跃的事务中最小的事务 ID

max_trx_id:表示创建ReadView时系统中应该分配给下一个事务的id值,当前最大事务ID+1

而判断数据记录可见性的逻辑就是通过readview和【行记录的隐藏字段trx_id】做对比的

image.png

判断规则:

  1. trx_id==creator_trx_id先将 Undo Log 最新数据行中的 trx_id 和 ReadView 中的 creator_trx_id 进行对比,如果他们两个值相同,则说明是在同一个事务中执行,那么直接返回当前 Undo Log 的数据行即可,如果不相等,则继续下面流程。

  2. trx_id<min_trx_id:如果 trx_id 小于 min_trx_id,则说明在执行查询时,其他事务已经提交此行数据了,那么直接返回此行数据即可,如果大于等于,则继续下面流程。

  3. trx_id>max_trx_id:如果 trx_id 如果大于等于 max_trx_id,则说明该行数据比当前操作执行的晚,当前行数据不可见,继续执行后续流程。

  4. min_trx_id<=trx_id<max_trx_id:trx_id 在 min_trx_id 和 max_trx_id 之间还分为以下两种情况:

    trx_id 在 m_ids 中:说明事务尚未执行完,该行数据不可被访问。

    trx_id 未在 m_ids 中:说明事务已经执行完,可以返回该行数据。

对于使用 已提交读可重复读 隔离级别的事务,必须保证读到已经提交的事务修改的记录,也就是说假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的。