文章目录1. 核心纠正MVCC 的边界2. 为什么你会产生“写不阻塞”的错觉场景对比3. “写-写”是如何阻塞的当前读4. 只有一种情况写看起来像“不阻塞”总结面试怎么说 进阶延伸在传统的 MySQL InnoDB 实现中MVCC 并没有解决“写-写”冲突它只解决了“读-写”冲突。如果两个事务同时尝试修改同一行数据它们依然会互相阻塞。让我们把这个容易产生误解的概念拆开来看彻底帮你打通任督二脉。1. 核心纠正MVCC 的边界在面试或技术讨论中一定要明确这个边界读-读不阻塞天然支持。读-写不阻塞这是 MVCC 的核心功劳通过 Undo Log 快照实现。写-写依然阻塞MVCC 并不处理这个靠的是行锁 / 锁机制。所以如果你觉得“写不应该被阻塞”那其实是一个误区。数据库必须保证原子性和一致性如果两个写操作同时修改同一行而不阻塞就会发生“覆盖更新Lost Update”灾难。2. 为什么你会产生“写不阻塞”的错觉可能是因为你在看文档时看到了类似“MVCC 提升了写的并发性”这样的话。这其实指的是写操作不再被读操作阻塞。场景对比没有 MVCC全是锁事务 A 正在读某行加了读锁S 锁。事务 B 想改这行必须等 A 读完释放锁。这时候写被读阻塞了。有了 MVCC事务 A 正在读快照读。事务 B 想改这行直接去修改最新版本并加行锁。B 不需要管 A 在干什么因为 A 读的是 Undo Log 里的历史版本。这时候写不被读阻塞。3. “写-写”是如何阻塞的当前读当你执行UPDATE、DELETE或者INSERT时InnoDB 执行的是当前读Current Read。取号事务尝试修改某行。加锁它必须先获取该行的X 锁排他锁。冲突如果另一个事务已经持有了这一行的 X 锁当前的事务就必须进入lock wait状态。MVCC 在哪此时 MVCC 只是在后台默默地为被修改的数据生成 Undo Log 版本好让那些“只读不改”的事务能看到旧数据。4. 只有一种情况写看起来像“不阻塞”那就是在分布式数据库或者某些特定的存储引擎如乐观锁机制的 NoSQL中采用的是CASCheck-And-Set或者写时拷贝Copy-on-Write。但在 MySQL 的 InnoDB 里写操作必须老老实实排队加锁。总结面试怎么说如果面试官问“MVCC 是不是让读写都不阻塞了”你可以这样优雅地回答“准确来说MVCC 实现了读-写的非阻塞。它通过版本链让读操作快照读不需要等待写操作释放锁。但是写-写操作之间依然是阻塞的。InnoDB 仍然需要通过行锁Record Lock来保证多个事务同时修改同一行数据时的一致性。所以 MVCC 的本质是**‘让读不被写阻塞’**而不是‘让写不被写阻塞’。” 进阶延伸如果你在研究Seata的AT 模式你简历里提到的你会发现它在分布式事务里实现了一套自己的“全局锁”那其实也是在解决“写-写”冲突防止脏写。理解了这一点你觉得在RR可重复读隔离级别下如果一个事务先SELECT了一行然后另一个事务把它删了并提交第一个事务再去UPDATE这行会发生什么