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,但允许其他事务读取这些行,而不允许修改或插入新的行。

相关推荐
寂寞旅行2 小时前
向量数据库Milvus的使用
数据库·milvus
闻哥3 小时前
Redis事务详解
java·数据库·spring boot·redis·缓存·面试
道亦无名3 小时前
aiPbMgrSendAck
java·网络·数据库
面向对象World6 小时前
正点原子Mini Linux 4.3寸800x480触摸屏gt115x驱动
linux·服务器·数据库
dinga198510266 小时前
mysql之联合索引
数据库·mysql
微风中的麦穗7 小时前
【SQL Server 2019】企业级数据库系统—数据库SQL Server 2019保姆级详细图文下载安装完全指南
大数据·数据库·sqlserver·云计算·个人开发·运维必备·sqlserver2019
zjttsh8 小时前
MySQL加减间隔时间函数DATE_ADD和DATE_SUB的详解
android·数据库·mysql
顾北128 小时前
SpringCloud 系列 04:Gateway 断言 / 过滤器 / 限流 一站式落地指南
java·开发语言·数据库
禹凕8 小时前
MYSQL——基础知识(NULL 值处理)
数据库·mysql
码云数智-大飞8 小时前
SQL Server 无法启动?常见原因及详细解决方法指南
数据库