惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MongoDB | Blog
MongoDB | Blog
博客园_首页
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
B
Blog RSS Feed
D
Docker
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
Recent Announcements
Recent Announcements
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
A
About on SuperTechFans
The GitHub Blog
The GitHub Blog
G
Google Developers Blog
V
V2EX
量子位
雷峰网
雷峰网
月光博客
月光博客
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
MySQL 的 MVCC:看不见的“时间机器”怎么帮你躲过脏读和幻读?
port smith · 2026-04-27 · via DEV Community

port smith

MySQL 的 MVCC:那台你从没启动过,却一直在为你倒带的“时间机器”

你有没有在图书馆借过一本《数据库原理》?翻开时目录还是旧版,而管理员其实在你借走后悄悄上架了修订版——但你完全不受影响。又或者,多人协同编辑一份文档,每人打开时看到的都是自己那一刻的快照,互不干扰。这并非魔法,而是 MySQL InnoDB 引擎中 MVCC(多版本并发控制)在 quietly work:一台无需你点开、不用你设置、却始终为你精准回溯数据状态的“隐形时间机器”。

一、快照、版本链与 ReadView:MVCC 的三驾马车

InnoDB 从不只存一行数据的一个版本。每行记录自带两个隐藏字段:trx_id(最后修改该行的事务 ID)和 roll_ptr(指向 undo 日志中前一版本的指针),由此串成一条“版本链”。当事务开启,InnoDB 并不复制整库,而是生成一个轻量级的 ReadView——相当于为这次查询配了一副“专属眼镜”。它记录三项关键信息:当前活跃事务 ID 列表、最小未提交事务 ID(min_trx_id)、最大已分配事务 ID(max_trx_id)。后续所有普通 SELECT 都依据这套规则判断:“这个版本,我能不能看见?”

判定逻辑极简:仅当某行版本的 trx_id 小于 min_trx_id,或等于当前事务 ID,或属于已提交且不在活跃列表中的事务,才对本次查询可见。

二、RR 与 RC:同一句 SQL,为何结果“变脸”?

核心差异,就在 ReadView 的生成时机。

✅ RC(读已提交):每次 SELECT 都新建 ReadView;

✅ RR(可重复读):仅事务首次 SELECT 时创建 ReadView,后续复用。

来个小实验(建议在空库执行):

CREATE TABLE t (id INT PRIMARY KEY, v INT);
INSERT INTO t VALUES (1, 10);
-- 事务 A(RR):START TRANSACTION; SELECT * FROM t; → 返回 (1,10)
-- 事务 B(RC):START TRANSACTION; UPDATE t SET v=20 WHERE id=1; COMMIT;
-- 事务 A 再次 SELECT * FROM t; → 仍返回 (1,10)(RR 复用快照)
-- 事务 C(RC)此时 SELECT → 立刻看到 (1,20)(新建 ReadView)

Enter fullscreen mode Exit fullscreen mode

RR 的“可重复读”,不是数据没变,而是你始终透过同一副眼镜看世界——时间被定格在第一次查询那一刻。

三、幻读:MVCC 解决了吗?答案是——一半。

普通 SELECT(即快照读)在 RR 级别下确实规避了幻读:新插入的行若 trx_id 大于 ReadView 的 max_trx_id,或属于未提交事务,一律不可见。但一旦触发 当前读(如 SELECT ... FOR UPDATEUPDATEINSERT ... SELECT),InnoDB 会绕过 MVCC,直接加锁并访问最新数据——此时若另一事务插入了满足条件的新行,幻读便真实发生。因此,RR 的“防幻读”本质是 MVCC + 间隙锁(Gap Lock)双保险:MVCC 负责让你“看不见”,间隙锁负责让别人“插不进”。

四、生产陷阱:Undo 日志爆满、长事务拖垮性能

MVCC 依赖 undo 日志保存历史版本。若长期不清理,undo 表空间持续膨胀,甚至触发 innodb_undo_log_truncated 告警。更危险的是长事务:它会让 ReadView 持有极老的 min_trx_id,导致大量旧版本无法回收,undo 日志堆积如山,最终拖慢整个实例。

三个立刻见效的优化动作:

  1. 定期查看 SHOW ENGINE INNODB STATUS,重点关注 History list length(历史链长度),超 10 万需警惕;
  2. 设置 max_execution_time = 30000(单位毫秒),自动中断超时查询;
  3. 执行 SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 300,及时 KILL 运行超 5 分钟的事务。

五、总结:MVCC 不是银弹,而是一场精密协奏

它不解决写-写冲突(仍需行锁),不替代应用层的数据校验,更不是 MyISAM 那种“无事务”的代名词。它的强大,源于与 InnoDB 存储引擎、隔离级别策略、锁机制的深度咬合。理解 MVCC,不只是记住 trx_id 规则,更是看清:每一次“看似无锁”的读,背后都有时间戳的精准裁决;每一次“理所当然”的一致性,都依赖 undo 日志的沉默承重。

真正的数据库高手,从不迷信机制——而是在读懂设计边界之后,让工具,真正为人所用。