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

相关推荐
拾忆,想起11 分钟前
TCP滑动窗口:网络世界的“智能流量阀门”
java·网络·数据库·网络协议·tcp/ip·php·哈希算法
懒羊羊不懒@22 分钟前
【MySQL | 基础】概念
数据库·mysql
yookay zhang34 分钟前
达梦新云文档数据库分享
数据库
laplace01233 小时前
Java八股—MySQL
java·mysql·oracle
熙客4 小时前
TiDB:分布式关系型数据库
java·数据库·分布式·tidb
你想考研啊7 小时前
oracle导出 导入
数据库·oracle
韩立学长9 小时前
基于Springboot的旧时月历史论坛4099k6s9(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
TDengine (老段)10 小时前
TDengine 字符串函数 CONCAT_WS 用户手册
android·大数据·数据库·时序数据库·tdengine·涛思数据
IT 小阿姨(数据库)10 小时前
PostgreSQL 之上的开源时序数据库 TimescaleDB 详解
运维·数据库·sql·postgresql·开源·centos·时序数据库
颜大哦11 小时前
linux安装mysql
linux·运维·mysql·adb