当前位置:网站首页>MySQL MVCC多版本并发控制
MySQL MVCC多版本并发控制
2022-06-23 05:59:00 【菜鸟~~】
文章目录
一、MVCC的概念
MVCC是多版本并发控制(Multi-Version Concurrency Control,简称MVCC),是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现已提交读和可重复读隔离级别的实现,也经常称为多版本数据库。MVCC机制会生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定的级别(语句级或事务级)的一致性读取。从用户的角度来看,好像是数据库可以提供同一数据的多个版本(系统版本号和事务版本号)。
MVCC多版本并发控制中,读操作可以分为两类:
- 快照读(非锁定读):读的是记录的可见版本,不用加锁。如 select做的都是快照读,会把已经commit的数据生成一个快照(这就可以防止不可重复读)
- 当前读:读取的是记录的最新版本,并且返回当前读的记录。如 insert,delete,update,select…lock in share mode/for update这些操作,都是读的是最新的数据。
MVCC:每一行记录实际上有多个版本,每个版本的记录除了数据本身之外,增加了其它字段(DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR)
在已提交读隔离级别,每次select查询时都重新生成快照(Read View)
在可重复读隔离级别,事务第一次select查询时,生成一个当前事务全局性的快照(Read View),并且只生成一次快照
快照内容读取原则:
- 版本未commit,无法读取生成快照
- 版本已commit,但是在快照创建后提交的,无法读取
- 版本已commit,但是在快照创建前提交的,可以读取
- 当前事务内自己的更新,可以读到
二、MVCC用于已提交读隔离级别
1. 解决脏读
设置隔离级别为已提交读并开启事务

可以看出已提交读解决了脏读问题。不管是已提交读还是可重复读,只要select,就会产生数据快照,以后查询的时候查询的都是快照上的数据,不会查最新的数据,这也就是非锁定读,效率比较高,不像串行化,都是通过锁来做事务间的并发互斥,而非锁定读都是在快照上进行的操作。
在已提交读隔离级别,每一次select都会产生一个新的数据快照,当事务1进行更改的时候,事务2又去select,重新产生数据快照(有可能和前面的快照相同),然而产生新的数据快照的前提是新的数据已经被事务正确commit,prepare状态的数据不会出现在快照中
数据有2种状态:prepare(未提交时)和commit(已提交)
事务2第二次select的时候,由于事务1并没有commit新的数据(数据处于prepare状态),当又一次产生数据快照时,产生的数据快照还是undo log回滚日志的链表指向的旧数据,这就解决了脏读问题
然而,在已提交读隔离级别依然会发生不可重复读的现象(两次查询,得到的数据内容不一样,属于正确读取的范围)
2. 不能解决不可重复读
已提交读不能防止不可重复读发生,事务2第一次select这条数据的时候,事务1还没有修改,所以MVCC生成的快照读是用原始数据生成的快照读,但是事务1现在把这条数据改了并且正常commit,符合生成数据快照时的基本要求,此时事务2又select这条数据,每一次select都会产生新的快照,这次就是拿新的数据产生快照。
3. 不能解决幻读
回滚并开启事务

发现同样的条件下查询的数据量不一样,出现了幻读,分析:
此时事务2再去select * from user where age=16;首先生成数据快照,先给数据拍照如下图:
然后再从里面找出age=16的记录
为什么一个事务能实时展现出另一个事务增加的满足同样查询条件的已提交的数据,导致我们这个事务出现幻读?
因为每一次select都会重新产生一次新的数据快照,其他事务增加了和当前事务查询条件相同的数据,并且已成功commit提交,导致当前事务再次以同样的条件查询时,数据多了!
三、MVCC用于可重复读隔离级别
1. 解决脏读
prepare状态的数据是不会出现在数据快照上的,对commit已提交的数据生成数据快照,然后在数据快照上查询。和已提交读分析的原因一样。
2. 解决不可重复读问题
可重复读第一次select产生数据快照,而且只产生一次。
设置可重复读隔离级别,回滚并开启两个事务
事务2第一次select产生了数据快照,因为在可重复读级别下,以后再select都不会产生数据快照
产生的数据快照如下:

事务1update,然后commit
update以后,表格如下所示:
我们事务2再次select id=12的数据,这时还是在第一次select拍照上查数据,解决了不可重复读。
如果事务2在事务1更新数据之前没有select过,那么更新之后执行select会产生数据快照,可以查到更新后的数据。
3. 不能完全解决幻读
先查看表的数据
回滚并开启事务

事务1生成的快照如下:
事务2第一次select是两条数据,事务1 insert之后,事务2再次select依然是两条,看似解决了幻读,其实只是部分解决(并不能完全解决幻读)
那我们看一下为什么是部分解决幻读
事务1 insert然后commit后,表格的数据应该是这样的
此时事务2update
可以看到update找到了id=24的数据,这就证明update做的是当前读(读最新的commit状态的数据),而不是快照读,因为快照上根本没有id=24的数据。
其实1000是事务1的ID,2000是事务2的ID
当前事务是可以看到自己事务修改、更新的数据的。
当事务2再次select的时候,就可以看到id=24的数据了,这就发生了幻读。
所以在可重复读级别下,并没有完全解决幻读问题
边栏推荐
猜你喜欢

Measurement principle and thickness measurement mode of spectral confocal

直播带货这么火,如何在小程序中实现视频通话及直播互动功能?

Open source ecology 𞓜 super practical open source license basic knowledge literacy post (Part 2)

解决挖矿病毒 sshd2(redis未设密码、清除crontab定时任务)

ssm + ftp +ueditor

Xxl-sso enables SSO single sign on

VS2013 FFMPEG环境配置及常见错误处理

xml dtd 记录

Miscellaneous things

Chrome删除重复书签
随机推荐
MySQL重做日志 redo log
MySQL的意向共享锁、意向排它锁和死锁
Topic35——34. Find the first and last positions of elements in a sorted array
Haas506 2.0 development tutorial -hota (only supports versions above 2.2)
【项目实训】多段线扩充为平行线
【STL】顺序容器之deque用法总结
【项目实训】线形箭头的变化
Mongodb record
光谱共焦的测量原理及厚度测量模式
js 动态创建a href 循环下载文件只能下载10个或者固定数目的问题
mingw-w64、msys和ffmpeg的配置与编译
Intentional shared lock, intentional exclusive lock and deadlock of MySQL
关于职业态度
Problem: when the attribute in the data object (defined data) in the access component is also the attribute in the object object, an error is reported
leetcode - 572. A subtree of another tree
【shell】Tree命令
Haas506 2.0 development tutorial - Advanced Component Library -modem SMS (only supports versions above 2.2)
Linux Installation mysql8.0.25
MySQL重做日志 redo log
中台库存中的实仓与虚仓的业务逻辑设计