首页 > 数据库 >MySQL(二十一)MVCC多版本并发控制

MySQL(二十一)MVCC多版本并发控制

时间:2023-05-09 14:12:52浏览次数:46  
标签:事务 加锁 快照 MySQL 并发 版本 MVCC id

MySQL(二十一)MVCC多版本并发控制


1 什么是MVCC

  • MVCC(Multiversion Concurrency Control)多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制,使得在InnoDB事务隔离级别下执行一致性读操作有了保障。
  • 就是为了查询一些正在被其他事务更新的值的时候,能够查到它们被更新之前的值,这样做就能在查询的时候不必等待更新事务的提交
  • MySQl中只有InnoDB支持MVCC,其他存储引擎不支持

2 快照读和当前读

  • MVCC在InnoDB中的实现主要是为了提高数据库的并发性能,用更好的方式处理读写冲突,做到即使有读写冲突,也能不加锁实现非堵塞并发读,这个读指的是快照读而不是当前读
  • 当前读实质上是一种加锁的操作,是悲观锁的体现;而MVCC是采用乐观锁的一种方式
2.1 快照读
  • 快照读又称作一致性读,对于普通的不加锁的简单SELECT都属于快照读,即不加锁的非堵塞读
  • 快照读的实现基于MVCC,在很多情况下,避免了加锁操作,降低了开销
  • 由于是多版本数据,所以快照读独到的可能不是最新的数据而是之前更新的历史版本
  • 快照读的前提是隔离级别不是可串行化可串行化快照读会退化为当前读
2.2 当前读
  • 当前读要求读取的是最新版本的数据
  • 还要求保证其他并发事务不能修改当前事务,会对读取的记录加锁
  • 加锁的SELECT(共享或排它锁)或者对数据进行增删改操作(自动添加排它锁)都会进行当前读

3 回顾

3.1 再谈隔离级别
image-20230508204516647

​ 在MySQL中默认的隔离级别是可重复读,从SQL标准的定义看它能解决脏读、不可重复读问题,但是不能解决幻读问题,如果想要解决幻读问题,需要提高隔离级别标准,设置为可串行化但响应地并发程度也会降低。

​ MVCC可以不使用可串行化的锁机制,而是通过乐观锁(MVCC )+ Next-key lock 临键锁的方式来解决幻读问题,可以在大多数情况下替代掉行级锁,降低系统的开销。

image-20230509094937068
3.2 隐藏字段、Undo log版本链

​ undo log的版本链,对于使用InnoDB存储引擎的表来说,它的聚簇记录中包含两个必要的索引列:

  • trx_id:每次事务对聚簇记录进行修改的时候,就会将该事务的id复制给trx_id隐藏列
  • roll_pointer:每次对每条聚簇索引进行改动的时候,都会将旧的版本信息写入undo log中,通过回滚指针就能找到记录修改前的信息

​ 比如插入一条记录,记录的示意图如下:

image-20230509095703376

insert log只在事务中起到回滚的作用,当事务提交之后,该类型的undo log记录就无效了,它占用的undo log segment也会被系统回收(undo log占用的页面链表要么被重用,要么被释放)

​ 假设两个事务id分别为10、20的事务分别对这条记录进行Update操作

image-20230509100311039

在InnoDB中,会对增删改操作自动添加排它锁,因此两个事务不会出现脏写的情况,也就是不会出现两个事务交叉着对同一条记录进行修改,必须等待第一个事务提交才能进行第二个事务

​ 每次对记录进行改动,都会记录一条undo log,每个undo log都包含创建它的事务id,每条undo log都会有一个roll pointerINSERT操作不会有,因为插入没有更新的版本),这些undo log通过roll pointer连接起来,串成一个链表,这个链表就成为undo log 版本链

image-20230509100559256

4 MVCC的实现原理--ReadView

​ MVCC的实现依赖于:隐藏字段Undo logRead View

4.1 什么是ReadView
  • 在MVCC中,多个事务对同一行记录进行更新会产生多个历史快照,这些记录保存在Undo Log里

  • Read View就是事务在使用MVCC机制在进行快照读操作时产生的快照

  • 快照记录创建这个Read View的事务id、活跃的事务中最小的id、系统最大的事务id,并且InnoDB会为每个事务构建了一个数组,用来记录并维护系统当前活跃事务的ID(活跃指的是启动了还没有提交)

  • 等到访问某条记录的时候,就可以根据上面记录的内容判断记录版本对当前事务可不可见

    • 如果Read Viewcreator_id当前事务的id相同,则意味着当前事务在访问它修改过的id,所以该记录版本可以被事务访问
    • 如果当前访问版本记录的trx_id小于Read Viewup_limit_id,则意味着修改该数据版本的事务已经提交,所以该版本的记录可以被当前事务访问
    • 如果当前访问版本记录的trx_id大于等于Read Viewlow_limit_id,则意味着创建该数据版本的事务是在ReadView生成之后才出现的,因此当前事务不能访问
    • 如果当前访问版本记录的trx_idRead Viewup_limit_idlow_limit_id之间,则需要判断trx_id是否在Read Viewtrx_ids活跃事务列表中,如果在则说明事务还没有提交当前事务不能访问,否则可以访问
4.2 ReadView的组成
  1. creator_id:创建这个Read View的事务id

  2. trx_ids:表示创建这个Read View的时候正在活跃的事务id列表

  3. up_limit_id:活跃的事务中最小的id

  4. low_limit_id:表示生成low_limit_id时系统应该分配给下一个事务的id值,low_limit_id是系统最大的事务id(而不是活跃的最大事务id)

    low_limit_id并不是trx_ids的最大值而是系统能够分配的事务id最大值,事务id是递增分配的,并且只有事务在进行增删改操作的时候才会分配事务ID。比如现在有1 2 5三个事务,那么id为5的事务提交后,一个新事务在生成ReadView的时候,trx_ids就包括1 2,up_limit_id就是1,low_limit_id就是6

举例

image-20230509103313272

​ 如上,此时如果有事务创建Read View,则

  • trx_ids=[trx2, trx3, trx5, trx8]
  • up_limit_id=trx2
  • low_limit_id=trx8+1
4.3 MVCC的整体流程

​ 当查询一条技术的时候,系统

  1. 首先获取查询操作的事务的版本号
  2. 获取当前系统的ReadView
  3. 将查询到的数据与ReadView中的事务版本号进行比较
  4. 如果不符合ReadView的规则,则通过回滚指针形成的Undo Log版本链undo log中获取符合规则的历史快照
  5. 返回符合规则的数据
4.4 隔离级别设计思路
  • 读未提交:能够读取未提交的事务修改的数据,所以直接读取最新的记录就可以,不必使用MVCC
  • 读已提交:不能读取未提交的事务修改的数据,并且不能进行重复读取,所以查询的时候每次都获取一次MVCCReadView视图
  • 可重复读:不能读取未提交的事务修改的数据,并且能进行重复读取,所以只在第一次查询的时候获取一次ReadView,之后查询都只查看已经生成的ReadView副本
  • 可串行化:InnoDB规定使用加锁的方式来访问记录
4.5 MVCC在可重复读下解决幻读问题

​ MySQL可以通过两种方式解决幻读问题

  • 读写加锁,也就是使用可串行化的隔离模式

  • 使用MVCC进行快照读,写使用临键锁

    添加的临键锁不会影响快照读,只会影响到想要获取锁的读操作

​ 可以回顾一下这一部分:MySQL在Repeatable Read隔离级别下是可以解决幻读问题的,解决的方案有两种:

  • 通过MVCC

    读操作利用多版本并发控制MVCC),写操作加

    MVCC就是生成一个ReadView,通过ReadView能够找到符合条件的记录版本(历史版本由undo log提供查询),查询语句执行查询已经提交的事务做出的更改,对于没由提交的事务和ReadView创建之后的事务做出的更改是看不到的。而写操作肯定是针对的最新版本的记录,因此读记录的历史版本和写操作的最新记录版本并不会冲突,也就是采用MVCC时,读写操作并不会冲突

    普通的SELECT语句在READ COMMITTED 和 REPEATABLE READ隔离级别下的读操作就是利用MVCC进行的读

    • READ COMMITTED:由于不会读取没有提交的事务修改的数据版本,因此避免了脏读问题
    • REPEATABLE READ:由于不会读取Read View创建之后的事务更改的数据(一个事务只有在第一次执行SELECT语句才会生成一个Read View,之后的SELECT语句都在复用),因此避免了可重复读和幻读问题
  • 通过加锁的方式

    读、写操作都采用加锁的方式

    在一些业务场景中,不允许读取数据的历史版本,即每次都需要去读取磁盘中最新的数据,这样也就意味着读操作也需要和写操作一样排队执行。

    如此一来,脏读不可重复读问题都得到了解决,因为读操作和写操作的串行执行,不会出现一个事务读取另一个未提交事务的数据以及一个事务读取过程中另一个事务修改数据提交导致前一个事务前后读取数据不一致的情况(第二个事务根本无法开始)

    标签:事务,加锁,快照,MySQL,并发,版本,MVCC,id
    From: https://www.cnblogs.com/tod4/p/17384677.html

相关文章

  • MySQL(十八)MySQL事务(二):事务的隔离级别
    MySQL(十八)MySQL事务(二):事务的隔离级别​ MySQL是一个客户端/服务器架构的软件,可以有若干个客户端与之连接,连接上之后都可以被称作是一个会话,每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是事务的一部分,因此对于服务器来说需要同时处理多个事务。由于事......
  • MySQL(十九)MySQL事务日志(一)RedoLog
    MySQL(十九)MySQL事务日志(一)RedoLog​ 事务的四种特性:原子性、一致性、持久性和隔离性都是基于什么机制实现的?事务的隔离性由锁机制实现而事务的原子性、一致性和持久性则由事务的redo和undo日志来实现的redolog是重做日志,提供再写入操作,恢复提交事务修改的页的操作......
  • mysql 索引
    mysql索引按存储方式区分: 一:b树,通常是使用b树这种方式,只有一个根节点,叶子节点之间彼此相连 二:hash,首先不能使用hash索引排序,并且它只支持等值索引,比如"=""in()""<=>"。 不支持键的部分匹配,因为计算hash值的时候是根据整体索引值来计算的。 建立hash索引相比b树需要更长的......
  • MySQL(十九)MySQL事务日志(二)UndoLog
    MySQL(十九)MySQL事务日志(二)UndoLog1undo日志概述​ redolog是事务持久性的保障,而undolog则是事务原子性和一致性的保证,如上图,在事务中更新数据的前置操作其实是需要将数据写入到undolog方便回滚。​ 事务需要保证原子性,也就是事务中的操作要么全部完成、要么全部不做。......
  • You have an error in your SQL syntax; check the manual that corresponds to your
    问题描述显示在条件查询的sql语句那里报错问题解决本来我是习惯了使用servlet写数据库操作的,然后就直接忽略掉了,或者说,直接忘记了在jsp里面的sql语句怎么正确书写了;经过查阅资料发现,查询语句是这样写的:Stringsql="select*frombookwhereid="+id;......
  • Centos7安装MySQL详细步骤(配置开机自启)
    MySQL检查系统是否安装过mysql//检查系统中有无安装过mysqlrpm-qa|grepmysql//查询所有mysql对应的文件夹,全部删除whereismysqlfind/-namemysql卸载CentOS7系统自带mariadb#查看系统自带的Mariadb[root@CDH-141~]#rpm-qa|grepmariadbmariadb-libs-5.5......
  • MYSQL查询【全部表】和表【所有字段】
    最近在做一些关于BI的东西。记录下。数据库查询全部表名称和备注信息只能查询表名SHOWTABLES; 查询表名和表备注SELECTTABLE_NAMEtablename,TABLE_COMMENTremarkFROMINFORMATION_SCHEMA.TABLESWHEREtable_schema="xxxx_xxxx"andT......
  • HTAP for MySQL 在腾讯云数据库的演进
    摘要:MySQL在充分利用多核计算资源方面比较欠缺,无法同时满足在线业务和分析型业务的客户需求,而单独部署一套专用的分析型数据库意味着额外的成本和复杂的数据链路。本次主题将介绍腾讯云数据库为满足此类场景而在HTAPforMySQL产品方面进行的尝试。2023首届云数据库技术沙龙MySQ......
  • mysql主从复制
    一、概述将主库的数据变更同步到从库,从而保证主库和从库数据一直。主要功能:数据备份、失败迁移、读写分离、降低单库读写压力二、原理1.主库会把数据变更记录在二进制日志文件Binlog中。2.从库连接主库,读取Binlog日志,并写入自身中继日志relaylog。3.slave重做中继日志,将......
  • mysql 8 安装
    1环境说明(1)基础环境操作系统:CentOSLinuxrelease7.4.1708(Core)配置:4c8GB100GBmysql版本:mysql-8.0.32-linux-glibc2.12-x86_64.tar.xz备份工具:percona-xtrabackup-8.0.32-26-Linux-x86_64.glibc2.17.tar.gz软件下载:wgethttps://downloads.percona.com/downloads/Per......