MVCC -MySQL多版本并发控制

MVCC是多版本并发控制,指的是一条数据记录会有多个版本,每次修改的时候会存储之前的版本,因此MVCC的控制是以一条数据为单位的而不是表。

MVCC能够实现启动的事务无锁地访问不同版本的数据,因此读(普通读)写操作不会受到阻塞。

MVCC有两个重要的概念:即版本链和readView

版本链:

版本链实现了多个版本的存储,其实现原理为当事务改变了数据表的某一条数据时,会附带两个隐藏字段的数据,一个是trx_id,即事务ID,一个是roll_pointer,是指向undolog的指针。

当事务为插入的时候,就会插入生成的trx_id以及roll_pointer,trx_id标识了事务唯一,而roll_pointer则指向mysql自带的一个undolog表,这张表里记录了这次事务的id和修改数据的主键和长度等信息。 然而,由于插入操作本身不会修改现有的行,而是创建新的行,因此这个新行没有前一个版本。数据库在提交该插入事务后,roll_pointer 通常会为空,因为没有旧版本需要回滚, 当这条插入事务提交后,其undolog就会被回收,因为插入数据前是没有回滚的意义的。所以对于插入操作,undolog只在事务未提交时有效,一旦事务提交就会回收。

当执行 UPDATEDELETE 操作时,trx_idroll_pointer 被更新。roll_pointer 指向的 undo log 包含了修改前的旧版本数据。这个 undo log 不仅记录了原始数据,还记录了 roll_pointer 的值,指向再之前的旧版本的 undo log 条目。通过这种方式,多个版本的记录被串联起来,形成所谓的"版本链"。

readView:

readView的作用是说明哪个版本对于新执行的事务而言是可见的,readView只会在有包含查询操作的事务执行的同时存在未提交的增删改事务才会创建,其本质是一个视图。

readView相关的有四个概念,即creator_id(当前事务id),m_ids(生成readView时还活跃的事务id,即还未提交的事务id),min_trx_id(活跃id的最小id),max_trx_id(生成readView时InnoDB将分配给下一个事务的ID的值)。

对于可见版本的判断是沿着版本链逐渐寻找老的版本,如果遇到合适的版本就返回。

判断条件如下:

  • 当trx_id==creator_id时,说明当前事务就是修改数据的事务,(例如在同一个事务中先进行修改再进行查询),所以可见。
  • 当trx_id<min_trx_id的时候,说明当前事务查询的版本是已经提交了的版本,所以可见。
  • 当min_trx_id<trx_id<max_trx_id的时候,如果此时trx_id在m_ids中,说明当前事务还没有提交,因此不可见,如果trx_id不在m_ids中,说明已提交,因此可见。
  • 当trx_id>=trx_max_id,说明修改这条数据的事务在当前事务生成readView的时候还未启动,所以不可见。

当隔离级别是读已提交时:

每一个含有查询的事务都会生成一个readView,而单纯的查询事务的creator_trx_id=0,然后根据判断条件选择最大的trx_id那个可见版本进行查询。

当隔离级别是可重复度时:

在第一次查询生成readView之后,后续的查询都共用这一个readView。

注意:MVCC并不能解决幻读的问题,因为MVCC是针对于数据行(即单条数据)进行的控制,当发生了插入和删除操作的时候,读取的数据集结构就发生了改变,即使对于删除操作而言在可重复度情况下readView是一个readView,但是读取的结果中行数仍然会少那一行,因此仍然会出现幻读。

以MVCC进行的读操作为快照读(即根据readView快照向表中数据进行读取),注意快照读不是从视图读而是按照视图提供的字段向数据表中读取相应的版本数据。

要解决幻读,需要实现当前读,即读取数据的最新数据版本,并且加锁以确保数据一致性。即使其他事物在当前读之后修改了数据,也会立即反映在当前读的结果中。

当前读会在要读取的数据中加锁,即间隙锁,锁定范围内的所有记录和间隙,防止其他事务在该范围内插入新数据。

显示使用间隙锁,可以在查询语句中使用如下结构:

SELECT ... FOR UPDATE:用于在当前事务中锁定所查询的行,并且锁定这些行之间的间隙,防止其他事务插入或删除这些记录。

SELECT ... LOCK IN SHARE MODE :类似于 FOR UPDATE,但允许其他事务读取这些行,而不允许修改或插入新的行。

相关推荐
WangYaolove13142 小时前
基于python的在线水果销售系统(源码+文档)
python·mysql·django·毕业设计·源码
山岚的运维笔记2 小时前
SQL Server笔记 -- 第18章:Views
数据库·笔记·sql·microsoft·sqlserver
roman_日积跬步-终至千里3 小时前
【LangGraph4j】LangGraph4j 核心概念与图编排原理
java·服务器·数据库
汇智信科3 小时前
打破信息孤岛,重构企业效率:汇智信科企业信息系统一体化运营平台
数据库·重构
野犬寒鸦3 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
霖霖总总3 小时前
[小技巧66]当自增主键耗尽:MySQL 主键溢出问题深度解析与雪花算法替代方案
mysql·算法
晚霞的不甘5 小时前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
市场部需要一个软件开发岗位5 小时前
JAVA开发常见安全问题:纵向越权
java·数据库·安全
海奥华25 小时前
mysql索引
数据库·mysql
2601_949593656 小时前
深入解析CANN-acl应用层接口:构建高效的AI应用开发框架
数据库·人工智能