当前位置: 首页 > article >正文

面试必问!MySQL 事务到底是怎么实现的?这篇文章讲透了

说实话这个问题我被问过不止一次。每次有人来问我 MySQL 事务是怎么回事我都发现大家普遍停留在「ACID 四个特性」这个层面背得挺溜但真要问你 MySQL 底层是怎么实现原子性的怎么保证崩了数据不丢怎么做到多个事务并发跑还互不干扰——很多人就开始含糊了。这篇文章我就把这块彻底说清楚。不搞那些花里胡哨的直接从底层机制讲起生产上遇到过的坑也会顺带提一嘴。先说说事务是什么事务这个概念说白了就是把一组操作捆绑成一个整体要么全部成功要么全部失败不允许中间状态存在。举个最经典的例子转账。A 给 B 转 500 块数据库层面是两步操作A 的账户减 500B 的账户加 500。这两步必须同时成功或者同时失败不然 A 扣了钱 B 没收到或者 B 收到了 A 没扣这都是灾难性的数据错误。这就是事务要解决的核心问题。MySQL 里事务主要是 InnoDB 引擎实现的MyISAM 不支持事务这个要先知道。ACID 大家都背过原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability。但背概念没用我们要知道 MySQL 是用什么技术手段实现这四个特性的。原子性→ 靠undo log持久性→ 靠redo log隔离性→ 靠锁 MVCC一致性→ 是上面三个共同作用的结果下面一个一个展开说。Undo Log原子性的保障undo log 翻译过来叫回滚日志。它的核心思想很简单在你修改数据之前先把原来的数据记下来万一事务失败了就拿这个日志把数据恢复回去。你执行了一条INSERTundo log 里就记一条DELETE你执行了UPDATEundo log 里就记一条把数据改回去的UPDATE你执行了DELETEundo log 里就记一条INSERT。这样当事务需要回滚的时候MySQL 就把 undo log 里的操作反向执行一遍数据就回到了事务开始之前的状态。有一点要注意undo log 一定是优先于数据修改落盘的这个顺序不能乱。如果数据先改了undo log 还没写这时候崩了你连回滚的依据都没有了。实际上 undo log 不只是用来回滚它还承担着 MVCC 的职责后面会说到。Redo Log持久性的保障redo log 这块是我觉得 MySQL 设计里最精妙的地方之一。先说问题背景。MySQL 的数据最终是存在磁盘上的但读写操作都是在内存里的 Buffer Pool 里进行的不是每次改完数据都立刻写磁盘。这样做是为了性能磁盘随机 IO 太慢了。但这就带来了一个风险数据在内存里改了还没来得及刷到磁盘MySQL 突然崩了数据就丢了。怎么解决redo log 就是答案。redo log 记录的是数据页的物理修改每次事务提交的时候不需要立刻把数据页刷到磁盘但必须先把 redo log 写到磁盘。redo log 是顺序写的顺序写磁盘的速度比随机写快很多这个性能差距在机械硬盘时代尤其明显。这个机制有个专业名字叫WALWrite-Ahead Logging意思就是先写日志再写数据。MySQL 崩溃重启之后会扫描 redo log把已经提交但还没来得及刷盘的数据重新应用一遍数据就恢复了。这就是为什么事务一旦提交就算服务器崩了数据也不会丢。redo log 有个重要的参数innodb_flush_log_at_trx_commit这个参数控制 redo log 的刷盘策略设置为1每次事务提交都强制刷盘最安全但性能最差设置为2提交时写到操作系统的缓存每秒刷一次盘折中方案设置为0每秒刷一次盘性能最好但崩溃可能丢 1 秒数据生产环境一般金融类业务设置 1对数据安全性要求没那么高的业务可以设置 2。设置 0 风险比较大不建议。-- 查看当前配置SHOWVARIABLESLIKEinnodb_flush_log_at_trx_commit;-- 查看 redo log 相关配置SHOWVARIABLESLIKEinnodb_log%;MVCC隔离性的核心机制这块是整个事务机制里最复杂的也是面试最爱考的。MVCC 全称 Multi-Version Concurrency Control多版本并发控制。它解决的核心问题是怎么让读操作不加锁同时还能保证数据的隔离性传统的做法是读写都加锁读的时候其他人不能写写的时候其他人不能读这样数据是安全了但并发性能很差。MVCC 的思路是给数据维护多个版本不同的事务看到不同版本的数据读操作基本不需要加锁。InnoDB 是怎么实现多版本的InnoDB 在每行数据上隐式地加了几个字段DB_TRX_ID最后一次修改这行数据的事务 IDDB_ROLL_PTR指向 undo log 的指针通过这个可以找到这行数据的历史版本DB_ROW_ID隐式的行 ID每次事务修改一行数据不会直接覆盖原来的数据而是创建一个新版本旧版本通过DB_ROLL_PTR串起来形成一个版本链。举个例子一行数据初始值age 20事务 AID100把它改成了 25事务 BID101又把它改成了 30这行数据就有了三个版本通过版本链串联在一起。Read View 是什么光有版本链还不够还需要一个机制来决定当前事务应该看哪个版本的数据这就是 Read View读视图的作用。Read View 里记录了几个关键信息当前活跃的事务 ID 列表m_ids最小活跃事务 IDmin_trx_id下一个待分配的事务 IDmax_trx_id创建这个 Read View 的事务 ID判断一个数据版本是否对当前事务可见规则大概是这样如果这个版本的DB_TRX_ID小于min_trx_id说明这个版本是在 Read View 创建之前就已经提交的可见如果DB_TRX_ID大于等于max_trx_id说明这个版本是在 Read View 创建之后才开始的事务改的不可见如果在这两者之间就看DB_TRX_ID是不是在活跃事务列表里在的话说明这个事务还没提交不可见不在的话说明已经提交了可见如果当前版本不可见就顺着版本链往前找直到找到一个可见的版本。隔离级别和 MVCC 的关系MySQL 有四个隔离级别读未提交、读已提交、可重复读、串行化。读未提交基本不用 MVCC直接读最新版本啥都不管脏读问题很严重生产上几乎不用。读已提交Read Committed每次执行 SELECT 都重新创建一个 Read View所以每次都能读到其他事务最新提交的数据。这个级别会有不可重复读的问题——同一个事务里两次查询同一行数据结果可能不一样因为中间有其他事务提交了修改。可重复读Repeatable Read这是 MySQL 的默认隔离级别。它在事务第一次执行 SELECT 的时候创建 Read View整个事务期间都复用这个 Read View所以不管其他事务怎么改你每次查到的都是一样的数据。这就是可重复读的含义。来看个具体的场景-- 事务 A 开始STARTTRANSACTION;SELECTageFROMuserWHEREid1;-- 读到 age 20-- 此时事务 B 把 age 改成了 25 并提交-- UPDATE user SET age 25 WHERE id 1; COMMIT;-- 事务 A 再次查询SELECTageFROMuserWHEREid1;-- 在 RR 级别下仍然读到 age 20COMMIT;在可重复读级别下事务 A 两次查询结果是一样的事务 B 的修改对 A 不可见因为 A 的 Read View 是在 B 提交之前创建的。串行化Serializable所有事务串行执行完全不存在并发问题但性能最差基本只在极端场景下用。幻读问题和间隙锁说到这里要提一个经典问题MVCC 能解决幻读吗答案是不能完全解决。幻读是指同一个事务内两次范围查询第二次查到了第一次没有的记录通常是其他事务插入了新数据。MVCC 通过 Read View 可以解决快照读普通 SELECT的幻读问题但如果你用的是当前读SELECT ... FOR UPDATE或者UPDATE、DELETE那就不走 MVCC 了是直接读最新数据这时候幻读就可能出现。InnoDB 解决这个问题用的是间隙锁Gap Lock和Next-Key Lock。Next-Key Lock 行锁 间隙锁它不只锁住符合条件的行还会锁住这些行之间的间隙防止其他事务在这个范围内插入新数据。-- 这条语句会加 Next-Key LockSELECT*FROMuserWHEREageBETWEEN20AND30FORUPDATE;-- 锁住了 age 在 20-30 范围内的所有行以及这个范围内的间隙-- 其他事务无法在这个范围内插入新记录这就是为什么 MySQL 在可重复读级别下能基本解决幻读问题但要注意这是在当前读的场景下靠锁来保证的不是靠 MVCC。事务提交和崩溃恢复的完整流程把前面说的串起来看看一个事务从开始到提交底层到底发生了什么事务开始分配事务 ID执行 SQL 操作修改 Buffer Pool 里的内存数据每次修改先写 undo log记录原始数据用于回滚和 MVCC再把修改记录到 redo log buffer事务提交时把 redo log buffer 里的内容刷到磁盘这步完成事务就算持久化了释放事务持有的锁后台线程异步把 Buffer Pool 里的脏页刷到磁盘数据文件崩溃恢复时扫描 redo log找到已提交但没有刷盘的事务重新应用找到未提交的事务用 undo log 回滚这个设计保证了数据既不会因为崩溃而丢失已提交的数据也不会因为崩溃而保留未提交的数据。生产上几个要注意的坑长事务是大忌。事务越长持有锁的时间就越长其他事务等待的时间就越长系统并发能力就越差。而且长事务会导致 undo log 不能被清理因为可能还有其他事务需要读历史版本undo log 会一直膨胀磁盘空间会被大量占用。我之前处理过一个案例一个业务同学写了个数据迁移脚本在一个事务里处理了几十万条数据跑了将近一个小时这期间 undo log 撑到了几十 GB把磁盘快打满了差点影响整个数据库服务。-- 查看当前活跃事务找出长事务SELECT*FROMinformation_schema.INNODB_TRXORDERBYtrx_started;-- 看看有没有跑了很久的事务SELECTtrx_id,trx_started,trx_state,trx_queryFROMinformation_schema.INNODB_TRXWHERETIMESTAMPDIFF(SECOND,trx_started,NOW())60;不要在事务里做外部调用。比如在事务里调用第三方接口、发消息队列这些操作耗时不可控会导致事务时间变长锁持有时间变长。正确的做法是先提交事务再做外部调用或者用异步的方式处理。隔离级别不是越高越好。串行化虽然安全但并发性能极差。大多数业务用可重复读就够了某些读多写少且对一致性要求不那么严格的场景用读已提交性能更好。autocommit 要注意。MySQL 默认开启自动提交每条 SQL 都是一个独立的事务。如果你用BEGIN或者START TRANSACTION开启了事务记得要COMMIT或者ROLLBACK不然事务会一直挂着。总结MySQL 事务的实现核心就是三个东西undo log、redo log、MVCC。undo log 保证了原子性事务失败可以回滚同时也是 MVCC 多版本数据的存储基础。redo log 保证了持久性通过 WAL 机制事务提交后数据不会因为崩溃而丢失。MVCC 加上锁机制保证了隔离性让并发事务之间互不干扰同时尽量减少锁的使用提升并发性能。这几个机制不是独立运作的它们相互配合共同构成了 InnoDB 事务体系。理解了这些再去看各种隔离级别的行为、幻读的成因、长事务的危害就都能说清楚了。下次面试官再问你 MySQL 事务是怎么实现的希望你不只是背 ACID而是能说出 undo log 怎么保证原子性redo log 为什么能保证持久性MVCC 的 Read View 是怎么判断版本可见性的。这才是真正理解了事务机制。如果觉得这篇文章对你有帮助欢迎点赞转发让更多人看到。我会持续分享生产环境中的运维实战经验MySQL 优化、故障排查、架构设计这些内容后续都会出关注不迷路。个人博客躬行笔记

相关文章:

面试必问!MySQL 事务到底是怎么实现的?这篇文章讲透了

说实话,这个问题我被问过不止一次。每次有人来问我 MySQL 事务是怎么回事,我都发现大家普遍停留在「ACID 四个特性」这个层面,背得挺溜,但真要问你 MySQL 底层是怎么实现原子性的,怎么保证崩了数据不丢,怎么…...

H5Maker开源编辑器:3步搭建你的专属H5创作平台

H5Maker开源编辑器:3步搭建你的专属H5创作平台 【免费下载链接】h5maker h5编辑器类似maka、易企秀 账号/密码:admin 项目地址: https://gitcode.com/gh_mirrors/h5/h5maker 想要快速制作精美的H5页面却苦于没有专业设计技能?H5Maker开…...

别再踩坑了!Element Plus侧边栏折叠动画卡顿?试试这个CSS样式和collapse-transition配置

Element Plus侧边栏动画卡顿优化实战:从CSS到性能调优全解析 当我们在企业级后台系统中使用Element Plus的侧边栏菜单时,折叠动画的流畅度直接影响用户体验。很多开发者都遇到过这样的场景:点击折叠按钮后,菜单项像被"粘住&q…...

红队新神器!哪吒网络安全:DeepSeek 驱动的终端 AI 渗透指挥台

最近安全圈又出了个超棒的开源工具!一个潜伏了很久的 Rust 项目突然发布,它就是哪吒网络安全(nezha_cyber)—— 专为红队演练、渗透测试和漏洞研究打造的终端 AI 指挥台,用 DeepSeek 大模型给安全人员赋能,…...

从Modbus RTU通讯协议入手,手把手教你用Python控制伺服电机(附时代超群AIMotor示例代码)

Python实战:基于Modbus RTU协议精准控制伺服电机全流程解析 伺服电机作为工业自动化领域的核心执行元件,其精确控制能力直接影响设备性能。我曾在一个半导体封装设备项目中,需要同时协调12台伺服电机完成微米级定位,当时使用Pytho…...

别再乱改代码了!Discuz X3.5论坛登录状态判断与页面跳转的3种正确姿势(附移动端适配)

Discuz X3.5登录状态判断与页面跳转的3种专业实现方案 在Discuz X3.5论坛开发中,登录状态判断与跳转逻辑看似简单,实则暗藏诸多技术细节。许多站长直接从网络复制代码片段,导致页面闪烁、SEO收录异常或移动端适配失效等问题。本文将深入剖析三…...

如何用VinXiangQi打造你的智能象棋AI助手:3个步骤快速上手

如何用VinXiangQi打造你的智能象棋AI助手:3个步骤快速上手 【免费下载链接】VinXiangQi Xiangqi syncing tool based on Yolov5 / 基于Yolov5的中国象棋连线工具 项目地址: https://gitcode.com/gh_mirrors/vi/VinXiangQi 想要拥有一个能自动识别棋盘、分析棋…...

智能作业车辆路径规划【附ROS仿真】

✅ 博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。 ✅ 如需沟通交流,扫描文章底部二维码。(1)Dijkstra全局路径与改进TEB局部规划融合:首先基于…...

终极指南:如何在Mac上完整支持Xbox控制器游戏体验

终极指南:如何在Mac上完整支持Xbox控制器游戏体验 【免费下载链接】360Controller TattieBogle Xbox 360 Driver (with improvements) 项目地址: https://gitcode.com/gh_mirrors/36/360Controller 你是否曾经满怀期待地想在Mac上体验主机游戏的畅快&#xf…...

从USB到以太网:一文搞懂不同标准(CRC-32/CRC-8)的Verilog并行实现差异

从USB到以太网:CRC校验的Verilog并行实现实战解析 在高速数字接口设计中,CRC校验如同一位沉默的哨兵,时刻守护着数据完整性。当工程师面对USB 3.0的CRC-32、以太网的CRC-32C或SATA的CRC-8等不同标准时,如何在FPGA中高效实现这些校…...

终极窗口尺寸强制调整工具:3步彻底解决顽固窗口问题

终极窗口尺寸强制调整工具:3步彻底解决顽固窗口问题 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 你是否遇到过那些无法调整大小的顽固窗口?老旧软件界面…...

为 OpenClaw Agent 框架配置 Taotoken 作为统一的模型提供商

为 OpenClaw Agent 框架配置 Taotoken 作为统一的模型提供商 1. 准备工作 在开始配置之前,请确保已安装 OpenClaw 框架并完成基本环境搭建。同时需要在 Taotoken 控制台获取有效的 API Key,并在模型广场确认要使用的模型 ID。Taotoken 提供的模型 ID 通…...

WaveTools鸣潮工具箱:终极免费工具箱解锁游戏新体验 [特殊字符]

WaveTools鸣潮工具箱:终极免费工具箱解锁游戏新体验 🚀 【免费下载链接】WaveTools 🧰鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools 你是否曾经因为《鸣潮》游戏卡顿而烦恼?是否因为多个账号切换繁琐…...

告别官网!在PyCharm里直接调教ChatGPT写Python代码(附飞机大战实战)

在PyCharm中打造AI编程助手:用ChatGPT插件开发飞机大战游戏 每次在浏览器和IDE之间反复切换查文档、调试代码时,你是否想过:如果有个懂编程的助手能直接嵌入开发环境会怎样?现在PyCharm的ChatGPT插件让这成为可能。不同于官网版本…...

如何让明日方舟干员成为你的桌面伙伴?5个简单步骤部署开源桌宠神器Ark-Pets终极指南

如何让明日方舟干员成为你的桌面伙伴?5个简单步骤部署开源桌宠神器Ark-Pets终极指南 【免费下载链接】Ark-Pets Arknights Desktop Pets | 明日方舟桌宠 (ArkPets) 项目地址: https://gitcode.com/gh_mirrors/ar/Ark-Pets 想让《明日方舟》中的干员突破次元壁…...

Go语言技能树实战:从并发模式到REST API的工程化演练

1. 项目概述:一个Go语言技能树的实战演练场 最近在GitHub上看到一个挺有意思的仓库,叫 guynhsichngeodiec/cc-skills-golang 。光看这个名字,你可能会有点懵,但点进去就会发现,这其实是一个围绕Go语言技能点构建的实…...

快速解锁VMware macOS支持:完整实战指南

快速解锁VMware macOS支持:完整实战指南 【免费下载链接】unlocker VMware Workstation macOS 项目地址: https://gitcode.com/gh_mirrors/unloc/unlocker 在Windows或Linux系统上运行macOS虚拟机,是许多开发者和技术爱好者的实际需求。VMware U…...

ARM架构TLB管理机制与性能优化实践

1. ARM架构TLB管理机制概述 在ARM架构的处理器中,TLB(Translation Lookaside Buffer)是内存管理单元(MMU)的核心组件,负责缓存虚拟地址到物理地址的转换结果。当操作系统修改页表时,必须及时使T…...

Flutter定位权限处理全攻略:从iOS弹窗到Android后台定位,一个Demo搞定所有坑

Flutter定位权限处理全攻略:从iOS弹窗到Android后台定位,一个Demo搞定所有坑 在Flutter应用开发中,定位功能几乎是LBS类应用的标配,但权限处理却让不少开发者头疼。iOS 14的精确定位临时授权、Android 10的后台定位权限、权限被永…...

Twinkle Tray显示器亮度管理终极指南:免费快速调节多显示器亮度

Twinkle Tray显示器亮度管理终极指南:免费快速调节多显示器亮度 【免费下载链接】twinkle-tray Easily manage the brightness of your monitors in Windows from the system tray 项目地址: https://gitcode.com/gh_mirrors/tw/twinkle-tray Twinkle Tray是…...

别再只盯着幅值了!用MatLab搞定CSI相位矫正,让你的无线定位更精准

别再只盯着幅值了!用MatLab搞定CSI相位矫正,让你的无线定位更精准 在无线感知与定位研究中,CSI(Channel State Information)的幅值信息长期占据着研究者的视线焦点,而相位信息却像被遗忘的金矿&#xff0c…...

Android设备管理终极指南:Escrcpy如何彻底改变你的工作流

Android设备管理终极指南:Escrcpy如何彻底改变你的工作流 【免费下载链接】escrcpy 📱 Display and control your Android device graphically with scrcpy. 项目地址: https://gitcode.com/GitHub_Trending/es/escrcpy 在移动开发、测试和设备管…...

Python人脸识别入门:除了face-recognition,你还需要知道dlib库的这些安装“玄学”

Python人脸识别开发者的必修课:深入解析dlib库的安装逻辑与底层原理 人脸识别技术正在从实验室走向日常生活,而Python开发者往往被一个看似简单的安装问题绊住脚步——dlib库的安装。这个隐藏在face-recognition库背后的C图形库,为何会成为无…...

PyTorch增量学习超快

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 PyTorch增量学习的超速优化:从边缘设备到实时AI的革命 目录 PyTorch增量学习的超速优化:从边缘设备到实时…...

从‘cp -r not specified’报错,聊聊Linux命令设计的‘潜规则’与学习心法

从‘cp -r not specified’报错,聊聊Linux命令设计的‘潜规则’与学习心法 第一次在终端里敲下cp folder1 folder2却看到cp: omitting directory的红色警告时,我盯着屏幕愣了三秒。这个看似"不友好"的错误提示,后来成了我理解Linux…...

告别SATA卡顿!5分钟搞懂NVMe SSD为啥这么快(附选购避坑指南)

告别SATA卡顿!5分钟搞懂NVMe SSD为啥这么快(附选购避坑指南) 当你按下开机键,盯着屏幕上转圈的加载图标;或是游戏载入时,看着进度条缓慢蠕动;又或是拷贝大型文件,进度百分比像老牛拉…...

RAGENativeUI:终极GTA模组界面开发指南,快速打造原生级游戏体验

RAGENativeUI:终极GTA模组界面开发指南,快速打造原生级游戏体验 【免费下载链接】RAGENativeUI 项目地址: https://gitcode.com/gh_mirrors/ra/RAGENativeUI 价值主张开篇:告别界面开发噩梦,拥抱高效创作时代 想象一下&a…...

别再问怎么装ipa了!从企业签到TF上架,iOS开发者最全的四种分发方案实战对比

iOS应用分发方案全解析:从企业签名到TestFlight上架实战指南 每次面对iOS应用分发这个老话题,总能看到开发者群里冒出各种"求推荐稳定签名服务"、"TF上架又被拒了怎么办"的求助。作为经历过数十个应用从内测到上线全周期的老手&…...

用Unity LayerMask玩出花:一个‘层’搞定游戏中的敌我识别、场景交互与UI管理

用Unity LayerMask玩出花:一个‘层’搞定游戏中的敌我识别、场景交互与UI管理 在游戏开发中,我们经常需要处理各种复杂的交互逻辑。想象一下,当玩家点击屏幕时,系统需要快速判断这次点击是针对敌人、可拾取物品还是UI按钮。传统做…...

利用 Taotoken 的 API Key 管理与访问控制功能实现团队权限分级

利用 Taotoken 的 API Key 管理与访问控制功能实现团队权限分级 1. 团队权限管理的核心需求 在中大型团队或企业环境中,不同成员或项目对大模型 API 的访问需求存在显著差异。开发团队可能需要高频调用测试环境模型,而产品团队只需访问生产环境&#x…...