像Git一样管理数据:深入解析数据库并发控制MVCC的实现

news/2025/12/8 22:05:20/文章来源:https://www.cnblogs.com/poemyang/p/19323810

像Git一样管理数据:深入解析数据库并发控制MVCC的实现

MVCC
多版本并发控制(Multi-version Concurrency Control, MVCC)是一种通过维护数据多个版本来实现并发控制的技术。其基本思想是为每次事务生成一个新版本的数据,在读数据时选择不同版本的数据即可以实现对事务结果的完整性读取。在使用MVCC 时,每个事务都是基于一个已生效的基础版本进行更新,事务可以并行进行,从而可以产生一种图状结构。
image

如图所示,基础数据的版本为1,同时产生了两个事务:事务A与事务B。这两个事务都各自对数据进行了一些本地修改,这些修改只有事务自己可见,不影响真正的数据。之后事务A首先提交,生成数据版本2;基于数据版本2,又发起了事务C,事务C继续提交,生成了数据版本3;最后事务B提交,此时事务B的结果需要与事务C的结果合并,如果数据没有冲突,即事务B没有修改事务A与事务C修改过的变量,那么事务B可以提交,否则事务B提交失败。
事务在基于基础数据版本做本地修改时,为了不影响真正的数据,通常有两种做法。
1)将基础数据版本中的数据完全拷贝出来再修改;
2)每个事务中只记录更新操作,而不记录完整的数据,读取数据时再将更新操作应用到用基础版本的数据从而计算出结果。
MVCC的设计理念深受版本控制系统(如Git)的影响,其工作流程与版本控制系统的操作流程高度相似。在事务处理中,上述两种策略各有优势,完整拷贝策略简单直观,但可能占用较多存储空间;增量记录策略则更为高效,能有效减少存储开销。
MVCC的工作流程在很大程度上类似于版本控制系统(如Git)的操作流程,可以说,Git等版本控制系统的设计理念深受MVCC思想的影响。

事务处理
MVCC重点不在于并发控制,而在于实现事务(Transaction)。假设在一个关系型数据库中,更新操作以事务进行,每个事务包括对若干行数据的更新操作。更新事务必须具有原子性,即事务中的所有更新操作要么同时生效,要么都不生效。
在事务无法生效,即需要进行事务回滚时,通常会依赖于回滚日志(Undo Log)。回滚日志是一种专门用于事务恢复的日志技术,它详细记录了事务在执行过程中对数据的所有修改。若事务失败或系统崩溃,回滚日志能够用于将数据恢复至事务开始前的状态。
以MySQL为例,在MVCC中,对于每次更新操作,旧值会被保存到一条回滚日志日志中,即它是该记录的旧版本。随着更新次数的增加,所有的版本都会通过回滚指针(Roll Pointer)连接成一个链表,称之为版本链。链首就是最新的记录,链尾就是最早的旧记录。
举个例子,比如有个事务A插入了一条新记录:insert into user(id, name) values(1, '张三')。
image

现在来了一个事务B对该记录的name做出了修改,改为“李四”。
在事务B修改该行数据时,数据库会先对该行加锁,然后把该行数据拷贝到回滚日志中作为旧记录,即在回滚日志中有当前行的拷贝副本。
拷贝完毕后,修改该行name为“李四”,并且修改该行的事务ID为当前事务B的ID, 并将回滚指针指向拷贝到回滚日志的副本记录,即表示上一个版本就是它,事务提交后,释放锁。
image

此时又来了个事务C修改同一个记录,将name修改为“王五”。
在事务C修改该行数据时,数据库也先为该行加锁,然后把该行数据拷贝到回滚日志中,作为旧记录,发现该行记录已经有回滚日志了,那么最新的旧数据作为链表的表头,插在该行记录的回滚日志最前面。
image

现在想回滚到事务B,name值为“李四”的时候,只需通过回滚日志的链表指针顺着列表找到对应的回滚日志日志,将旧值恢复到数据行即可。

image

隔离级别
事务隔离级别是数据库系统中用于控制并发访问的机制,以确保数据的一致性和完整性。常见的事务隔离级别包括:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、序列化(Serializable)。
1)读未提交:读未提交隔离级别允许事务读取其他事务未提交的数据,可能导致脏读(Dirty Read)。写操作可能使用锁,但读操作不等待其他事务的锁释放。

transaction T1 {// 不使用锁read(data);// 写操作write(data);commit();
}transaction T2 {// 不使用锁read(data); // 可能从T1读到未提交的数据// 写操作write(data);commit();
}

2)读已提交:只允许事务读取其他事务已提交的数据,防止脏读。读操作通常使用共享锁(Shared Lock),且在读取后立即释放。写操作使用排他锁(Exclusive Lock),直到事务提交时释放。

transaction T1 {// 写操作使用排他锁lock(exclusive, data);write(data);commit();// 释放排他锁unlock(exclusive, data);
}transaction T2 {// 读操作使用共享锁lock(shared, data);read(data); // 只读取已提交的数据// 读取数据以后,立即释放共享锁unlock(shared, data);// 写操作使用排他锁lock(exclusive, data);write(data); commit();// 释放排他锁unlock(exclusive, data);
}

3)可重复读:确保事务在整个过程中读取的数据一致,防止不可重复读。读操作使用共享锁,并保持直到事务结束。写操作使用排他锁直到事务结束。此外,为防止幻读,可能还需要使用间隙锁(Gap Lock),以锁定数据间隙。

transaction T1 {// 写操作使用排他锁lock(exclusive, data);write(data);commit();// 释放排他锁unlock(exclusive, data);
}transaction T2 {// 读操作使用共享锁lock(shared, data);read(data); // 在整个事务中读取一致的数据// 间隙锁隐式通过查询条件锁定范围(如`WHERE id BETWEEN 1 AND 10`)lock(gap, range_data);read(range_data); // 锁定间隙,防止幻读 // 写操作使用排他锁lock(exclusive, data);write(data);commit();// 释放共享锁、间隙锁和排他锁unlock(exclusive, data);unlock(gap, range_data);unlock(shared, data);
}

3)序列化:确保事务完全隔离,防止幻读,提供最高的隔离级别。使用范围锁(Range Lock)等机制,锁定数据的范围,确保事务之间的完全隔离,防止幻读。

transaction T1 {// 对读和写操作,使用范围锁lock(range, data);read(data);write(data);commit();// 释放范围锁unlock(range, data);
}transaction T2 {// 对读和写操作,使用范围锁lock(range, data);read(data); // 避免幻读write(data);commit();// 释放范围锁unlock(range, data);
}

MySQL默认选用可重复读作为事务隔离级别,这主要得益于其通过多版本并发控制机制,在事务启动时即创建数据快照。这一设计确保了同一事务内多次读取操作的结果保持一致,从而有效规避了读已提交级别下可能出现的不可重复读问题。
与此同时,InnoDB存储引擎通过运用间隙锁和临键锁(Next-Key Lock)技术,对索引范围进行锁定,显著降低了幻读现象(多次读取同一数据范围时,由于其他事务的插入或删除操作,导致每次读取的结果集不同)的发生概率。这是读已提交级别所无法实现的,因为该级别无法对索引范围进行如此精细的锁定。
尽管在并发写场景下,读已提交级别的性能可能稍胜一筹,但可重复读级别通过快照读(无需加锁)与当前读(需加锁)的巧妙结合,在保障数据一致性的同时,也维持了较高的系统性能。
此外,MySQL在设计上更倾向于优先避免数据异常,特别是在处理银行账户、金融交易等关键业务场景时,数据的一致性和完整性至关重要。当然,用户仍可根据实际需求,手动将事务隔离级别切换至读已提交,以适应高并发写入场景的特殊要求。

总结:从硬抗到疏导,驾驭流量的艺术
缓存层设计需在即时响应和扩展性之间权衡:本地内存访问速度快,但容量有限;跨节点共享数据则会增加网络延迟。同时,要防范缓存穿透(过滤无效请求)、缓存击穿(对热点数据进行加锁控制)和缓存雪崩(分散缓存过期时间)等问题。
消息队列通过异步解耦机制,兼顾实时性与系统容错能力。Kafka利用分区顺序写入特性处理海量数据流,RocketMQ则借助二次确认与补偿机制,确保资金交易等场景无差错。
数据库层借助日志追加记录操作轨迹,采用版本快照隔离读写操作。查询时访问固定版本的数据,避免锁冲突;更新时生成新版本,确保事务的完整性。
并发系统设计的精髓,并非是追求单一组件的极致性能,而是一种关于“流动”与“控制”的艺术。它要求不再将压力视为需要硬抗的敌人,而是将其视为需要引导和疏解的能量。通过分层设计,将一个巨大而不可控的压力问题,分解为一系列更小、更清晰、更易于管理的子问题,并在每一层都做出最恰当的权衡与取舍。

很高兴与你相遇!如果你喜欢本文内容,记得关注哦!!!

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

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

相关文章

决策单调性(四边形不等式)学习笔记

CF321E Ciel and Gondolas \[dp_{k,i}=\min\{dp_{k-1,j}+w(j+1,i)\} \\ w(l,r)= \sum_{l \le i < j \le r} u(i,j) \]\(w(x,y)\) 满足四边形不等式,证明:Submission 352461026 P4767 [IOI 2000] 邮局 加强版 \[dp…

Classic Papers in Programming Languages and Logic | 阅读计划

来自 Classic Papers in Programming Languages and Logic 个人相比科研更喜欢纯粹的阅读(狗头),也感觉需要空闲时间探索一下经典论文,让 Gemini 帮我生成了一个阅读计划,最好能读下来:建议日期 主题单元 阅读论…

13.结构型 - 适配器模式 (Adapter Pattern)

适配器模式 (Adapter Pattern) 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁 意图: 将一个类的接口转换成客户希望的另外一个接口; 适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起…

CodeBuddy AI IDE:全栈AI创建平台实战

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

廊坊婚介所见证:放下挑剔的女人,幸福来得很快

在廊坊的一个小区门前,李珂总是喜欢把自己设定成“对未来丈夫的高标准”。她喜欢高大英俊,学历不低于硕士,收入稳定且在行业中有一定声望。对她来说,外表和地位才是婚姻成功的核心。于是她在网上投了不少简短而精致…

Tauri 窗口拖拽功能偶尔失效问题修复总结

窗口拖拽功能偶尔失效问题修复总结 问题描述 在 Tauri 应用的 Launcher 窗口中,用户发现拖拽功能存在一个奇怪的现象:✅ 输入框区域(wrapper):拖拽功能从不失效,非常可靠 ❌ 输入框上方区域(header 的其他部分,…

应用 SQLAlchemy 操作单表:以 SQLite 用户表为例的完整实战指南

应用 SQLAlchemy 操作单表:以 SQLite 用户表为例的完整实战指南2025-12-08 21:52 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !imp…

12-8午夜盘思

1、大盘无忧; 2、情绪方面:安记食品5连板,情绪周期强势延续;三市成交2万亿,抱团风格回归; 3、存储芯片:以存储芯片板块指数为锚点,板块上涨2.89%,板块强势;本质还是存储芯片涨价的故事;10cm方向,德明利领头…

MyBatis参数加解密

一、概述 在MyBatis中通过拦截器实现SQL参数加密/结果集解密是数据安全的常见场景,核心是拦截参数处理环节(加密入参)和结果集处理环节(解密出参)。适配Spring Boot3 + MyBatis环境。核心思路拦截点 作用 拦截接口…

基于Hadoop+数据可视化+机器学习随机森林预测算法+智能AI大模型+协同过滤推荐算法的青少年饮食习惯数据分析与可视化平台的设计与实现(精品源码+精品论文+上万材料集+答辩PPT)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

PyTorch推理扩展实战:用Ray Data轻松实现多机多卡并行

单机 PyTorch 模型跑推理没什么问题,但数据量一旦上到万级、百万级,瓶颈就暴露出来了:内存不够、GPU 利用率低、I/O 拖后腿,更别说还要考虑容错和多机扩展。 传统做法是自己写多线程 DataLoader、管理批次队列、手…

成膜助剂出口厂商有哪些?有出口资质的成膜助剂供应商名单推荐

成膜助剂作为涂料、胶粘剂等行业的核心功能性辅料,其供应稳定性、产品质量及出口服务能力直接影响下游产业发展。2025年,随着环保政策升级与国际贸易格局优化,具备出口资质、合规性强的成膜助剂厂商与贸易公司愈发受…

CF1994G

CF1994G因为异或每个位是独立的,只需要处理进位即可。 因此,考虑从低到高枚举每一位,记录进位个数,令 \(dp(i, j)\) 表示到第 \(i\) 位,进了 \(j\) 位的方案数。暴力枚举 \(0/1\) 转移即可。 时间复杂度:\(O(nk)…

2025婴儿车性价比排行榜首选:UPPAbaby MINU V3如何以轻便全能理念重新定义价值标准(附权威认证)

一、轻便婴儿车市场的价值认知革新 根据《2024中国母婴消费白皮书》(中国家庭教育学会发布)数据显示,在选购婴儿车时,87.3%的消费者将"轻便性"列为首要考量因素,但同时也有76.8%的用户担心轻便设计会牺…

陈阅视觉摄影培训机构发展历程

陈阅视觉摄影培训机构,成立于2009年,10多年来,陈阅视觉秉承“让摄影更加简单”的办学使命。 引进国外先进视觉传达课程体系,并结合国内特点,独立研发PLTA摄影教学系统,大力培养摄影与视频制作人才,有力推动国内…

hive ddl dml hivesql命令大全

SELECT T.sname,T.ctfid,T.gender,t.address,count(*) OVER(PARTITION BY T.sname) AS FM_CNTFROM test_db.room3 T WHERE T.address like "%北京%" AND instr(T.ctfid,310)>0 ORDER BY FM_CNT DESC;sel…

杭州刑事案件法律咨询找谁?刑事律师推荐

遇到刑事案件,时间就是生命。杭州刑事案件法律咨询找谁?今天给大家推荐一家专业的刑事辩护律所。 刑事案件为什么要尽早找律师? 黄金37天很关键,刑事拘留期:最长37天这个阶段律师能做什么:会见当事人了解案情;申…

【AI】第一篇:语言模型的前世 n-gram的简单介绍

1. N-gram 是什么?核心逻辑与“N”的含义 N-gram 是自然语言处理(NLP)中一种基于统计的语言模型,其核心思想是:一个词的出现概率,可以由它前面 N-1 个词来预测。它把文本按照连续的 N 个词(或字符)切分成片段(…

【12.11 直播】时序数据库 IoTDB FAQ 全面解答|下一期聊什么?你来决定!

集中解答你最想知道的问题,你还想了解什么?请告诉我们!🤔你在用时序数据库 IoTDB 时,是否也遇到过这些“灵魂拷问”: 🚀为什么我的查询无法执行? 💡树模型、表模型到底该如何选? 🔑如何与现有系统进行高…

12/8

今天满课,全是专业课,写了个Java系统,后端打不开,气死我了,晚上还要写统一建模语言