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: