MySQL-多版本并发控制MVCC

文章目录


一、多版本并发控制MVCC

MVCC是多版本并发控制(Multi-Version Concurrency Control),是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现已提交读和可重复读隔离级别的实现,也经常称为多版本数据库。MVCC机制会生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本(系统版本号和事务版本号)。事务的隔离性就是锁机制加MVCC 体现的。

MVCC多版本并发控制中,读操作可以分为两类:

1、快照读 (snapshot read)

读的是记录的数据快照,可以理解给数据拍了一张照片,不用加锁。如select

2、当前读 (current read)

读取的是当前事务记录的最新数据库版本,并且返回第一次select数据快照的记录。如insert,delete,update,select...lock in share mode/for update

已提交读和可重复读的底层实现原理 :通过MVCC多版本并发控制实现并发读取方式:快照读 。InnoDB提供了两个读取操作:锁定读 和非锁定读 。锁定读相关内容在锁机制里有提到,间隙锁、排它锁与共享锁等;非锁定读就是MVCC提供的快照读,它实现依赖于依赖底层的一个技术,undolog回滚日志;
undolog回滚日志的主要作用:事务发生错误时回滚rollback,提供MVCC的非锁定读(快照读),查快照上的数据而不是最新的数据;

二、undo log(回滚日志)

undo log:回滚日志,保存了事务发生之前的数据的一个版本,用于事务执行时的回滚操作,也就是rollback操作;同时也是实现多版本并发控制(MVCC)下读操作的关键技术,提供MVCC的非锁定读(快照读)。

实现回滚日志的两个关键:DB_TRX_ID:事务ID 、 DB_ROLL_PTR:回滚指针

通过上面的图片可以了解到,每一行记录实际上有多个版本 ,每个版本的记录除了数据本身之外,增加了其它字段 ;在记录行中隐式的记录了事务ID和回滚指针 ,这些隐式数据是给MySQL看的:

1、开启事务时,MySQL会给事务分配事务ID,同一个事务的事务ID是不变的,不同的事务ID不同;

2、事务修改后的数据,放在表中原来的位置上,修改之前的数据会被放置在undo log中(缓存中);旧数据与新数据通过回滚指针链接,类似链表的结构,通过链表就可以找到之前的旧数据,实现回滚操作;

二、已提交读

已提交读:可以解决事务并行的脏读问题,但是不能解决不可重复读和幻读问题。

sql 复制代码
//设置事务的隔离级别为 已提交读
set tx_isolation='READ_COMMITTED';

1、已提交读如何解决脏读问题? :

每次select都会产生一次新的数据快照,前提是数据被事务成功commit过了,在数据没有被commit之前,每次读的数据都是第一次select的结果;当事务成功commit之后,select产生最新的数据快照,此时会发生不可重复读、幻读 ;
2、为什么已提交读无法解决不可重复读、幻读?

因为每次select都会产生一次新的数据快照,其它事务更新以后成功commit,会导致当前事务再select的时候产生了数据更新后的数据快照,从而发生不可重复读和幻读。

三、可重复读

可重复读:可以解决事务并发产生的脏读、不可重复读问题;一定程度上解决幻读问题。

sql 复制代码
//设置事务的隔离级别为 可重复读
set tx_isolation='REPEATABLE-READ';

1、如何解决脏读问题?

也是通过数据快照解决的脏读问题;
2、如何解决不可重复读?

在可重复读 隔离级别下,数据快照只在第一次select时候产生,不会因为其它事务成功commit就改变当前的数据快照。当前事务再次select时,仍然查看的是第一次select的数据快照。

3、为什么能部分解决幻读 问题?

但是在事务执行update时,进行当前读,会读取到其它事务成功commit的数据;此时当前的事务发生更新,再执行select时,会将修改后的数据也显示出来,显示的结果就是第一次select的数据快照和修改后的数据


总结

由于MVCC,所以每一行记录实际上有多个版本,快照内容读取原则:

1、版本未提交无法读取生成快照 ;

2、版本已提交,但是在快照创建后提交的,无法读取 ;

3、版本已提交,但是在快照创建前提交的,可以读取 。所以在已提交读隔离级别下会产生不可重复读;

4、当前事务内自己的更新,可以读到 。所以在可重复读隔离级别下会产生幻读。

相关推荐
程序猿老A1 分钟前
轻量应用服务器怎么用phpcms搭建网站?
android
FlightYe2 小时前
视界原理之3D视频(三):解码和显示
android·linux·3d·ffmpeg·音视频·android runtime
syagain_zsx2 小时前
ODB 与 MySQL:C++ 里的 ORM 实践(类即表、事务铁律与查询封装)
开发语言·数据库·c++·mysql·工具库·1024程序员节
时间售卖铺3 小时前
MySQL 备份
运维·数据库·mysql·云原生
ttyyttemo3 小时前
Kotlin 协程中的热数据源与冷数据源
android
FlightYe3 小时前
linux系统编程(十七):内存管理基础
android·linux·ffmpeg·音视频·android runtime
夏幻灵3 小时前
MySQL 学习第一天:从数据库创建到 SQL 基础增删改查
mysql
瑞克-桑切斯3 小时前
mysql二进制日志定时备份
adb
蒲公英内测分发3 小时前
智能家居厂商有多个产品线,包装上的 App 下载入口该共用还是分开?
android·人工智能·数码相机·机器人·智能家居·智能硬件
shunwahma3 小时前
MySQL 替代选型,为什么首选 OceanBase 集中式?
数据库·mysql·oceanbase