问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

MySQL多版本并发控制原理-MVCC

创作时间:
作者:
@小白创作中心

MySQL多版本并发控制原理-MVCC

引用
1
来源
1.
https://cloud.tencent.com/developer/article/2484053

MySQL的多版本并发控制(MVCC)是一种重要的并发控制机制,它通过维护数据的多个版本来解决读写冲突,从而提高数据库的并发性能。本文将详细介绍MVCC的工作原理,并通过具体案例帮助读者理解其核心概念。

MVCC实现的目的

MVCC多版本并发控制实现的主要目的,就是为了解决数据库的读与写的并发冲突,提高并发性能。核心就是说,在读与写冲突的时候,尽最大可能不去加锁。

基于数据库的读与写实际上区分为几种:

第一:读与读

读与读实际并不会存在并发冲突,因为读并不涉及到数据库数据的变更。

第二:写与写

写与写实际也不会存在问题。因为写是一定会涉及数据库数据的变更的。所以当两个线程过来并发写的时候,那只能通过锁来解决,哪个线程拿到了锁,那就哪个线程去写。

第三:读与写

读与写是我们在数据库的操作中,需要考虑最多的情况了。因为在实际的业务中,基本都是读多写少的业务。所以在这种情况 下,我们就需要着重考虑如何来提高数据库的性能了。

为什么读与写我们不直接使用锁来处理。谁拿到了锁谁就来写,这里其实很好回答,就是为了性能。锁是影响整个数据库性能的最大问题之一。

MVCC的原理

简单的来说:MVCC就是将一条数据的所有历史版本都以链表的形式存储。不同的事务可以来访问整个链表中不同时期的数据版本快照。

这样的话。对于读来说可以去读取对应历史的版本,而写的话就可以写最新版本。互不冲突。

对于实现这样一个链表。mysql会基于每条数据来增加两个重要的字段

DB_TRX_ID: 创建或者修改数据的事务ID
这个字段记录的就是哪个事务来创建的这条数据。事务ID是系统分配的一个自增的数据,永远都从小到大。

DB_ROLL_PTR:回滚指针,指向记录的上一个版本。
这个字段记录的就是前一个事务的数据

例子

我们以一个实际的案例展示一下它的显示形式
下面这个图里面,每一行代表的都是这一条数据 的一个版本。
这个表里有2个字段 id 、name 。 另外两个显示的字段DB_TRX_ID DB_ROLL_PTR 是系统字段。

  1. 第一次事务,事务id : 100 进行修改name 为 mysql
  2. 第二个事务,事务id : 200 来修改name 为sql 时。数据库表中的数据被修改成 sql ,但事务200的DB_ROLL_PTR指针会指向事务100的修改记录,这样就形成了一个链路。
  3. 第三个事务,事务id : 300 来修改name 为mvvc .此时事务id300的修改就是最新数据。且DB_ROLL_PTR会指向事务200的数据。
    整个的MVCC存储链路就是这样的一个原理。

但我们会想到。为什么数据库我看到的永远都是最新的。当然,这里的链路数据是存储在undo日志中的。
所以当事务进行回滚时,就可以通过这个链路找到对应的事务数据。

如何来通过链路找到对应的事务数据

我们来了解一下2个概念

当前读

当前读就是读取数据的最新版本。其他的事务不能修改记录。
例如:insert 、update 、delete 、select ... for update 等这些执行语句都是当前读,读取数据的最新版本。

快照读

快照读就是读取MVCC版本链路中的某一个版本,不需要加锁
例如:select 读取的就是当前事务中的快照数据。

read view读视图

读视图是一个很重要的概念,它才是如何找到对应版本的事务的数据核心。
所谓读视图,实际上是记录并维护了系统当前事务的活跃事务id .哪些是活跃事务id ? (创建并未提交的事务)
我们看一下实际的案例如何来寻找对应版本数据:
下面的图中:有3个事务 100 、200 、300 ,活跃事务有 205 、255 、300 。也就是说只有300是未提交的。100和200 已经提交了。

  1. 当新事务301来查询数据时,首先读取了事务id=300的数据,也就是mvcc这条数据。但是事务301发现事务300是活跃事务(未提交事务),那事务300的值mvcc是不可见的。所以向下读取undo日志进行数据查找 。
  2. 通过事务id=300的这条数据的DB_ROLL_PTR指针在undo日志中找到了事务id=200这条数据
  3. 读取了事务id=200这条数据,发现事务id=200这条事务已经提交了,所以获取事务id=200这条数据。也就是值为:sql.

第二个例子:
下面的图中:有3个事务 100 、200 、300 ,活跃事务有 205 、255 、300 。也就是说只有300是未提交的。100和200 已经提交了。

  1. 当历史事务150来查询数据时,首先读取了事务id=300的数据,也就是mvcc这条数据。但是事务150发现事务300是活跃事务(未提交事务),那事务300的值mvcc是不可见的。所以向下读取undo日志进行数据查找 。
  2. 通过事务id=300的这条数据的DB_ROLL_PTR指针在undo日志中找到了事务id=200这条数据
  3. 读取了事务id=200这条数据,发现事务id=200这条事务已经提交了,但是事务200大于事务150.也就是说事务200是在150后面产生的事务。那对于事务150来说,也是不可见的。所以继续向下读取undo日志进行数据查找
  4. 通过事务id=200的这条数据的DB_ROLL_PTR指针在undo日志中找到了事务id=100这条数据
  5. 与上面的流程一样。找到事务id100且已提交,于是读取数据为 : mysql

当然了。如果是事务300来读取数据,那返回 的数据肯定 是其本身的数据了。也就是 mvcc

总结

总体来说,MVCC是一种强大的多版本并发控制,能解决mysql读写冲突中的并发效率问题。尽可能少的去加锁,来提高并发效率。
本文简明扼要的介绍了MVCC的目的及实现原理并通过实际的案例来说明了如何去查找快照。很好的理解MVCC的版本控制是如何做到的。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号