MVCC多版本并发控制实现的主要目的,就是为了解决数据库的读与写的并发冲突,提高并发性能。
核心就是说。在读与写冲突的时候,尽最大可能不去加锁。
基于数据库的读与写实际上区分为几种:
读与读实际并不会存在并发冲突,因为读并不涉及到数据库数据的变更。
写与写实际也不会存在问题。因为写是一定会涉及数据库数据的变更的。所以当两个线程过来并发写的时候,那只能通过锁来解决,哪个线程拿到了锁,那就哪个线程去写。
读与写是我们在数据库的操作中,需要考虑最多的情况了。因为在实际的业务中,基本都是读多写少的业务。所以在这种情况 下,我们就需要着重考虑如何来提高数据库的性能了。
为什么读与写我们不直接使用锁来处理。谁拿到了锁谁就来写,这里其实很好回答,就是为了性能。锁是影响整个数据库性能的最大问题之一。
简单的来说:MVCC就是将一条数据的所有历史版本都以链表的形式存储。不同的事务可以来访问整个链表中不同时期的数据版本快照。
这样的话。对于读来说可以去读取对应历史的版本,而写的话就可以写最新版本。互不冲突。
对于实现这样一个链表。mysql会基于每条数据来增加两个重要的字段
DB_TRX_ID: 创建或者修改数据的事务ID
这个字段记录的就是哪个事务来创建的这条数据。事务ID是系统分配的一个自增的数据,永远都从小到大。
DB_ROLL_PTR:回滚指针,指向记录的上一个版本。
这个字段记录的就是前一个事务的数据
我们以一个实际的案例展示一下它的显示形式
下面这个图里面,每一行代表的都是这一条数据 的一个版本。
这个表里有2个字段 id 、name 。 另外两个显示的字段DB_TRX_ID DB_ROLL_PTR 是系统字段。
整个的MVCC存储链路就是这样的一个原理。
但我们会想到。为什么数据库我看到的永远都是最新的。当然,这里的链路数据是存储在undo日志中的。
所以当事务进行回滚时,就可以通过这个链路找到对应的事务数据。
我们来了解一下2个概念
当前读就是读取数据的最新版本。其他的事务不能修改记录。
例如:insert 、update 、delete 、select ... for update 等这些执行语句都是当前读,读取数据的最新版本。
快照读就是读取MVCC版本链路中的某一个版本,不需要加锁
例如:select 读取的就是当前事务中的快照数据。
读视图是一个很重要的概念,它才是如何找到对应版本的事务的数据核心 。
所谓读视图,实际上是记录并维护了系统当前事务的活跃事务id .哪些是活跃事务id ? (创建并未提交的事务)
我们看一下实际的案例如何来寻找对应版本数据:
下面的图中:有3个事务 100 、200 、300 ,活跃事务有 205 、255 、300 。也就是说只有300是未提交的。100和200 已经提交了。
第二个例子:
下面的图中:有3个事务 100 、200 、300 ,活跃事务有 205 、255 、300 。也就是说只有300是未提交的。100和200 已经提交了。
当然了。如果是事务300来读取数据,那返回 的数据肯定 是其本身的数据了。也就是 mvcc
总体来说,MVCC是一种强大的多版本并发控制,能解决mysql读写冲突中的并发效率问题。尽可能少的去加锁,来提高并发效率。
本文简明扼要的介绍了MVCC的目的及实现原理并通过实际的案例来说明了如何去查找快照。很好的理解MVCC的版本控制是如何做到的。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 [email protected] 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 [email protected] 删除。