MVCC(多版本并发控制)介绍及实现原理

一、什么是MVCC?

MVCC(Multi-Version Concurrency Control,多版本并发控制)是数据库中用于解决并发访问问题的一种机制。它通过为数据维护多个版本,让读写操作在不同版本上独立进行,从而避免了传统锁机制中读写冲突导致的性能损耗(如读操作不会阻塞写操作,写操作也不会阻塞读操作)。

MVCC的核心目标是:在保证事务隔离性的前提下,提高数据库的并发性能。它广泛应用于支持行级锁的数据库(如MySQL的InnoDB、PostgreSQL等),尤其在读已提交(Read Committed)可重复读(Repeatable Read) 隔离级别中发挥关键作用。

二、MVCC的实现原理

MVCC的实现依赖于三个核心组件:数据的隐藏列回滚日志(Undo Log)ReadView(读视图)。三者协同工作,使得事务能够访问到符合其隔离级别的数据版本。

1. 数据的隐藏列

InnoDB存储引擎会为表中的每一行数据添加三个隐藏列,用于记录版本信息和事务相关数据:

  • DB_TRX_ID:记录最后一次修改该行数据的事务ID(6字节)。每次事务对行数据执行INSERT/UPDATE/DELETE操作时,都会将当前事务的ID写入该列。
  • DB_ROLL_PTR:回滚指针(7字节),指向该行数据的回滚日志(Undo Log),通过该指针可以找到数据的上一个版本。
  • DB_ROW_ID:行ID(6字节),当表没有主键或唯一索引时,InnoDB会用该列生成聚簇索引,确保每行数据有唯一标识。
2. 回滚日志(Undo Log)

回滚日志是MVCC实现多版本的基础,用于保存数据被修改前的旧版本。

  • 作用
    • 当事务需要回滚时,通过Undo Log恢复数据到修改前的状态(支持事务的原子性);
    • 为MVCC提供数据的历史版本,供其他事务读取(支持并发读写)。
  • 生成时机
    当事务执行INSERT/UPDATE/DELETE时,InnoDB会先将数据的旧版本写入Undo Log,再修改实际数据。
    • INSERT:Undo Log记录新插入的行信息,事务回滚时直接删除该行;
    • UPDATE/DELETE:Undo Log记录修改前的行数据,事务回滚时通过回滚指针恢复旧版本。
  • 版本链
    多次修改同一行数据时,Undo Log会形成一条“版本链”:每次修改后,新数据的DB_ROLL_PTR指向旧版本的Undo Log,旧版本的DB_ROLL_PTR再指向更早的版本,直至最初版本。

回滚日志为什么在update和delete时不会被立即删除,而insert之后可以立即删除?

update和delete之后还会被mvcc或者是快照读用到**,这里举个mvcc还需要回滚日志的例子**
MVCC(多版本并发控制)通过回滚日志来实现数据多版本管理,以解决并发事务中的读 - 写冲突等问题,在可重复读隔离级别下体现得较为明显。以下是一个基于MySQL的InnoDB存储引擎的例子:

  1. 假设当前有三个事务,事务ID分别为100、200、300。
  2. 事务200先执行了一条SQL语句:UPDATE user SET name = '小王3号' WHERE id = 1,此时数据库会将修改前的记录相关信息写入回滚日志,然后修改实际数据,并将数据的trx_id更新为200。
  3. 接着事务200提交。
  4. 之后事务100开始执行查询语句,此时会生成一个ReadView,视图数组为(100, 300)min_id为100,max_id为300。
  5. 然后事务300执行了一条SQL语句:UPDATE user SET name = '小王4号' WHERE id = 1,数据库同样会将修改前的记录(即name = '小王3号')写入回滚日志,再修改实际数据,将trx_id更新为300。
  6. 此时事务100再次执行查询语句,根据MVCC的规则:
    • row的trx_id落于min_idmax_id之间,且不在视图数组中,说明这个版本是已经提交的事务生成的,是可见的。
    • 事务300的trx_id为300,在min_idmax_id之间,但在视图数组中,所以其修改后的结果对事务100不可见。
    • 事务200的trx_id为200,也在min_idmax_id之间,不在视图数组中,所以事务100会根据回滚日志找到事务200修改前的记录,查询结果为name = '小王3号'

通过这个例子可以看到,MVCC利用回滚日志构建数据的旧版本,配合ReadView机制,让事务100在事务300已修改数据并提交的情况下,仍然能查询到符合可重复读规则的结果,体现了回滚日志在MVCC中的重要作用。

3. ReadView(读视图)

ReadView是事务在读取数据时生成的一个“快照”,用于判断当前事务能看到哪些版本的数据。它本质上是一组用于过滤数据版本的规则,包含四个核心参数:

  • m_ids:当前活跃(未提交)的事务ID列表。
  • min_trx_id:活跃事务中最小的事务ID。
  • max_trx_id:系统为下一个事务分配的ID(即当前最大事务ID+1)。
  • creator_trx_id:生成该ReadView的事务ID。
4. 版本可见性判断规则

事务读取数据时,会根据ReadView的参数,对数据的DB_TRX_ID(最后修改事务ID)进行判断,决定是否可见:

  1. DB_TRX_ID == creator_trx_id:数据是当前事务自己修改的,可见。
  2. DB_TRX_ID < min_trx_id:修改该数据的事务在当前事务启动前已提交,可见。
  3. DB_TRX_ID > max_trx_id:修改该数据的事务在当前事务启动后才开始,不可见(需通过回滚指针找更早版本)。
  4. min_trx_id ≤ DB_TRX_ID ≤ max_trx_id
    • DB_TRX_IDm_ids中(事务仍活跃):不可见(需找更早版本);
    • DB_TRX_ID不在m_ids中(事务已提交):可见。

如果当前版本不可见,事务会通过DB_ROLL_PTR沿着Undo Log的版本链向上查找,直到找到符合规则的可见版本。

三、不同隔离级别下的MVCC行为

MVCC的具体表现与事务隔离级别相关,主要差异在于ReadView的生成时机

  • 读已提交(Read Committed)
    每次执行SELECT时都会重新生成ReadView。因此,事务在两次查询之间若有其他事务提交,可能会看到新提交的数据(“不可重复读”)。
  • 可重复读(Repeatable Read)
    仅在事务第一次执行SELECT时生成ReadView,之后的查询复用该ReadView。因此,事务在整个生命周期中看到的数据版本是一致的(“可重复读”)。
四、MVCC的优势
  1. 读写不冲突:读操作通过访问旧版本数据,无需等待写操作释放锁;写操作仅锁定当前版本,不影响读操作。
  2. 隔离级别灵活:通过ReadView的生成时机和版本判断规则,适配不同隔离级别(读已提交、可重复读)。
  3. 支持事务回滚:结合Undo Log,确保事务失败时数据可恢复(原子性)。
总结

MVCC通过“隐藏列记录版本”、“Undo Log维护历史版本链”、“ReadView过滤可见版本”三者的配合,实现了多版本数据的并发访问。它既避免了传统锁机制的性能瓶颈,又保证了事务的隔离性,是现代数据库高效处理并发的核心技术之一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90148.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

密码学基础概念详解:从古典加密到现代密码体系

一、引言&#xff1a;为什么我们需要密码学&#xff1f; 在数字化时代&#xff0c;信息已成为核心生产要素&#xff0c;而信息安全则是保障社会运转的基石。当我们在电商平台输入银行卡密码时&#xff0c;当我们通过即时通讯工具发送私密消息时&#xff0c;当企业在云端存储核心…

小鹏汽车视觉算法面试30问全景精解

小鹏汽车视觉算法面试30问全景精解 ——智能驾驶 车路协同 视觉创新:小鹏汽车视觉算法面试核心考点全览 前言 小鹏汽车作为中国智能电动汽车的创新引领者,致力于通过AI与自动驾驶技术推动智能出行的变革。小鹏视觉算法团队深耕自动驾驶感知、车路协同、智能座舱、3D重建…

程序是如何生成的-以c语言为例

一&#xff0c;序言 从代码到能跑的程序&#xff0c;整个过程就像 “把外文翻译成母语&#xff0c;再组装成能直接用的东西”&#xff0c;一步步来更清楚&#xff1a; 源代码&#xff08;程序员写的代码&#xff0c;如C语言文件&#xff09;↓ 预处理&#xff08;处理#开头的命…

风险识别清单:构建动态化的风险管理体系

在项目管理实践中&#xff0c;风险识别是确保项目成功的关键环节。PMBOK提出的风险提示清单&#xff08;Prompt List&#xff09;为项目团队提供了一个系统化的思考框架&#xff0c;帮助突破个人经验局限&#xff0c;实现更全面的风险覆盖。这一工具的价值不仅在于其提供的标准…

从“点状用例”到“质量生态”:现代软件测试的演进、困局与破局

测试的三次范式跃迁业务高速迭代下的四大困局质量工程化&#xff1a;流程、平台、度量三位一体左移与右移&#xff1a;把缺陷扼杀在摇篮&#xff0c;也把监控铺到坟墓自动化金字塔的再平衡&#xff1a;UI、API、单元、契约、e2e数据驱动测试&#xff1a;从“拍脑袋”到“科学实…

【C++】继承和多态扩展学习

目录 1. 菱形虚拟继承原理剖析 1.1.虚基表 2. 单继承和多继承的虚函数表深入探索 2.1 单继承虚函数表深入探索 2.2 多继承虚函数表深入探索 ​编辑 2.3 菱形继承、菱形虚拟继承 3. 继承和多态考察的一些常见问题 1. 菱形虚拟继承原理剖析 继承的文章中我们讲到C的多继承…

Visual Studio Code 远端云服务器开发使用指南

目录 一、下载安装 1、官方下载 2、下载加速方案 二、基于Ubuntu系统的开发环境搭建方案 1、开发环境配置 2、云服务器架构 3、工作流程关系 4、总结 三、推荐插件 1、免配置插件 1. Remote-SSH - 远程登录Linux服务器 2. C/C - 必备的C/C开发插件 3. C/C Extensi…

技术演进中的开发沉思-41 MFC系列:定制 AppWizard

MFC开发&#xff0c;最为重要的无非就是用“MFC AppWizard” 对话框做开发了&#xff0c;第一次使用感觉像拆收音机的孩子 —— 左边是项目类型选择&#xff0c;右边是一堆打勾的选项&#xff0c;点完 “完成”&#xff0c;屏幕上就冒出了能直接编译运行的窗口程序。那时还不知…

Libevent(3)之使用教程(2)创建事件

Libevent(3)之使用教程(2)创建事件 Author: Once Day Date: 2025年6月29日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 本文档翻译于&#xff1a;Fast portable non-bl…

Kotlin 作用域函数 let 的实现原理

Kotlin 中的 let 是一个 标准库扩展函数&#xff0c;它广泛用于作用域函数&#xff08;Scope Functions&#xff09;中&#xff0c;尤其适用于对可空对象&#xff08;nullable&#xff09;做非空判断并执行代码块的场景。 示例代码 val name: String? "123" name?…

从FDTD仿真到光学神经网络:机器学习在光子器件设计中的前沿应用工坊

FDTD仿真与光学神经网络的基础概念 FDTD&#xff08;时域有限差分&#xff09;是一种数值方法&#xff0c;用于求解麦克斯韦方程组&#xff0c;广泛应用于光子器件设计。光学神经网络通过光波导、衍射元件等物理结构实现矩阵运算&#xff0c;具有低能耗、高并行的优势。 机器学…

在Ubutu22系统上面离线安装Go语言环境【教程】

0.引言 Go语言&#xff08;又称Golang&#xff09;是Google开发的一种静态强类型、编译型、并发型编程语言&#xff0c;由Robert Griesemer、Rob Pike和Ken Thompson于2007年开始设计&#xff0c;2009年正式发布。 1.到官网下载压缩包 2.从win10系统离线上传压缩包给ubuntu22…

CMake实践:CMake3.30版本之前和之后链接boost的方式差异

目录 1.背景 2.boost引入CMake时机 3.CMake 3.30 之前&#xff08;含 3.29&#xff09;链接 Boost 的方式 4.CMake 3.30 及之后链接 Boost 的方式 5.CMake3.30后引入Boost的步骤 6.迁移建议&#xff08;3.30 之前 → 3.30 之后&#xff09; 7.CMake 3.30 移除FindBoost的…

告别挂马风险!PBootCMS完美替代方案BadouCMS

开发企业网站时一直比较喜欢用pbootcms,标签套用很简单&#xff0c;使用也方便。 但是pbootcms一直有被挂马的问题&#xff0c;官方好像也不怎么更新了&#xff01;换过好几个cms&#xff0c;比如eyoucms、dedecms、帝国等等&#xff0c;感觉都不怎么能用得习惯&#xff0c;还…

开发者如何集成AI绘画?智创聚合API简化Midjourney接入

在 AI 绘画领域&#xff0c;Midjourney 的大名如雷贯耳&#xff0c;其强大的图像生成能力&#xff0c;能将我们脑海中的奇思妙想&#xff0c;迅速转化为精美的视觉画面&#xff0c;深受设计师、艺术家以及广大创意爱好者的青睐。然而&#xff0c;使用 Midjourney 的过程中&…

pycharm回车、删除、方向键和快捷键等不能使用原因

解决方法 &#xff1a;菜单栏中的Tools取消勾选Vim Emulator 原因 &#xff1a;新版的pycharm安装中&#xff0c;默认安装了vim扩展&#xff0c;一旦安装了pycharm在编写代码时会默认使用Vim编辑器

修复ffmpeg.dll丢失错误|6种解决ffmpeg.dll方法详细教程

看到电脑提示“ffmpeg.dll丢失”&#xff0c;很多人会懵。ffmpeg.dll 是个处理视频、音频的关键文件。它要是没了或坏了&#xff0c;软件就打不开或直接闪退。常见原因是软件安装不全、文件被删、或者中病毒。下面说说它是干嘛的&#xff0c;再给解决办法。一.ffmpeg.dll 到底是…

OkHttp 与 Stetho 结合使用:打造强大的 Android 网络调试工具链

前言在 Android 应用开发过程中&#xff0c;网络请求的调试一直是一个重要但具有挑战性的环节。Facebook 开发的 Stetho 是一个强大的调试工具&#xff0c;当它与 OkHttp 结合使用时&#xff0c;可以为我们提供前所未有的网络请求洞察能力。本文将详细介绍如何将这两者结合使用…

LangGraph教程10:LangGraph ReAct应用

文章目录 ReAct 预构建的代理 向 ReAct 代理添加记忆 向 ReAct 代理添加系统提示 向 ReAct 代理添加人机交互 ReAct 官方文档地址:https://langchain-ai.github.io/langgraph/how-tos/#prebuilt-react-agent 中文文档地址:https://www.aidoczh.com/langgraph/how-tos/#react…

安卓第一个项目

测试所有摄像头 安卓CameraX&#xff1a;https://developer.android.com/media/grow/spatial-audio?hlzh-cn 1、MainActivity.java // 定义包名 package com.mms.densenapplication;// 引入 AppCompatActivity&#xff0c;支持兼容性更强的 Activity import androidx.appcompa…