程序员

多版本并发控制 MVCC

2022-09-13  本文已影响0人  真正的飞鱼

介绍多版本并发控制

多版本并发控制技术(Multiversion Concurrency Control,MVCC)

技术是为了解决问题而生的,通过 MVCC 我们可以解决以下几个问题:

  1. 读写之间阻塞的问题:通过 MVCC 可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。

  2. 降低了死锁的概率:这是因为 MVCC 没有使用锁,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。

  3. 解决一致性读的问题:一致性读也被称为快照读,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交更新的结果。

MVCC 的思想

MVCC 是通过数据行的历史版本来实现数据库的并发控制。

简单来说 MVCC 的思想就是保存数据的历史版本。这样一个事务进行查询操作时,就可以通过比较版本号来判断哪个较新的版本对当前事务可见。

InnoDB 对 MVCC 的实现

MVCC 没有正式的标准,所以在不同的 DBMS 中,MVCC 的实现方式可能是不同的。

InnoDB 对 MVCC 的实现主要是通过 版本链 + ReadView 结构完成。

版本链存储记录的多个版本

先介绍聚簇索引记录的隐藏列,再介绍 Undo Log 版本链


对于使用 InnoDB 存储引擎的表来说,它的聚簇索引记录中都包含 3 个隐藏列

  1. db_row_id:隐藏的行 ID。在没有自定义主键也没有 Unique 键的情况下,会使用该隐藏列作为主键。

  2. db_trx_id:操作这个数据的事务 ID,也就是最后一个对该数据进行插入或更新的事务 ID。

  3. db_roll_ptr:回滚指针,也就是指向这个记录的 Undo Log 信息。Undo Log 中存储了回滚需要的数据。

事务ID

事务执行过程中,只有在第一次真正修改记录时(比如进行 insert、delete、update 操作),才会被分配一个唯一的、单调递增的事务 ID,如果没有修改记录操作,按照一定的策略分配一个比较大的事务 ID,减少分配事务 ID 的锁竞争。每当事务向数据库写入新内容时, 所写的数据都会被标记操作所属的事务的事务ID。


在 InnoDB 存储引擎中,版本链由数据行的 Undo Log 组成。

每次对数据行进行修改,都会将旧值记录到 Undo Log,算是该数据行的一个旧版本。

Undo Log 有两个重要的属性:db_roll_ptr、db_trx_id

版本链如下图所示。这样如果我们想要查找历史快照,就可以通过遍历回滚指针的方式进行查找。

1644822603680-293f8716-0b36-4053-ba87-00230e3e6ed5.png

ReadView 判断版本链中的哪个较新的版本对当前事务是可见的

ReadView 用来判断版本链中的哪个较新的版本对当前事务是可见的。

ReadView 中主要包含 4 个比较重要的属性:


有了这个 ReadView,这样在访问某条记录时,就可以用 ReadView 来判断版本链中的哪个较新的版本对当前事务是可见的。

如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断

可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对当前事务完全不可见,查询结果就不包含该记录。

ReadView 的生成时机

MVCC 可以防止脏读,也可以防止不可重复读。

防止脏读 和 防止不可重复读 实现的不同之处就在:ReadView 的生成时机不同


对于隔离级别为 读未提交 的事务来说,直接读取记录的最新版本即可。

对于隔离级别为 串行化 的事务来说,InnoDB 存储引擎使用加锁的方式来访问记录。

对于隔离级别为 读已提交 和 可重复读 的事务来说,都必须保证只能读到已经提交的事务修改的数据,不能读到未提交的事务修改的数据。

参考资料

MySQL 是怎样运行的:从根儿上理解 MySQL - 小孩子4919 - 掘金课程 (juejin.cn)

上一篇下一篇

猜你喜欢

热点阅读