MVCC多版本并发控制


介绍

MVCC多版本并发控制是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现读已提交和可重复读隔离级别。

实际上就是保存了数据在某个时间节点的快照
每行数据实际上隐藏了两列,创建时间版本号,过期(删除)时间版本号,每开始一个新的事务,版本号都会自动递增

例子: 假设我们插入两条数据

此时小明去执行查询,此时current_version=3

select * from user where id <= 3;

同时,小红在这个时候开启事务去修改id=1的记录,current_version=4

update user set name = '张三三' where id=1;

执行成功后的结果

如果此时小黑删除id=2的数据,current_version=5,执行后的结果是这样的

MVCC原理是查找创建版本小于或等于当前事务版本,删除版本为空或者大于当前事务版本

小明实际查询的结果是这样的

select * from user where id<=3 and create_version<=3 and (delete_version>3 or delete_version is null);

最后小明查询到的id=1的名字还是‘张三’,并且id=2的记录也能查询到。这样做是保证事务读取的数据是在食物开始前就已经存在的,要么是食物自己插入或者修改的

解决幻读:

场景:用户注册时,我们先查询用户名是否存在,不存在就插入

小明开启事务current_version=6查询名字为’王五’的记录,发现不存在。 小红开启事务current_version=7插入一条数据,结果是这样:

小明执行插入名字’王五’的记录,发现唯一索引冲突,无法插入,这就是幻读。此时current_version为8,即上面的数据都能读取到

数据库MVCC如何做到可重复读隔离级别?

  • 利用MVCC的快照

刚刚也提到了,快照技术是当今主流使用的手段。那么为什么快照可以确保可重复读隔离级别呢?从快照的本质来看,它表达的是数据库历史的某个一致性状态,事务所读取的数据和当前时刻数据库状态没有关系,只和这个一致性状态有关系,也就是读一致性。例如:

t0时刻,数据库中有a=10,b=10,此时这就是一个一致性状态。

t1时刻,某个读事务Tr开始,将t0时刻的一致性状态作为快照,读取a的值=10。

t2时刻,某个写事务Tw开始,为b执行+10,为a执行-10,并提交。此时数据库当前状态为a=0,b=20。

t3时刻,Tr读取b的值。但是由于Tr采用了快照读技术,数据库当前状态和Tr一毛钱关系没有,它只关心t0时刻的状态,所以读取到的值依然是10。此时就算事务Tr再读取a的值也一样,读取的结果依然同样为10。




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 2379. Minimum Recolors to Get K Consecutive Black Blocks
  • 2471. Minimum Number of Operations to Sort a Binary Tree by Level
  • 1387. Sort Integers by The Power Value
  • 2090. K Radius Subarray Averages
  • 2545. Sort the Students by Their Kth Score