MySQL 事务隔离级别与 MVCC 深度解析

引言

从并发问题出发,彻底理解 MySQL 为什么这样设计事务隔离

一、为什么需要事务隔离级别?

在并发数据库系统中,多个事务同时读写同一份数据是常态。如果不加任何控制,就会引发各种数据一致性问题,例如:

  • 一个事务读到了另一个事务尚未提交的数据
  • 同一事务中,两次查询结果不一致
  • 查询过程中"凭空多出"一些记录

这些问题统称为并发读问题 ,而 事务隔离级别(Isolation Level),正是数据库在「性能」和「一致性」之间做出的不同权衡方案。

二、MySQL 支持的四种事务隔离级别

SQL 标准定义了四种隔离级别,MySQL(InnoDB)全部支持。

读未提交(Read Uncommitted)

特点
  • 一个事务可以读到另一个事务尚未提交的数据
问题
  • 脏读(Dirty Read)
示例
复制代码
事务A:update account set balance = 0 where id = 1; (未提交)
事务B:select balance from account where id = 1; → 读到 0
事务A:rollback;

B 读到的数据是从未真正存在过的

评价
  • 几乎不加任何隔离
  • 实际生产环境基本不用

读已提交(Read Committed)

Oracle 的默认隔离级别

特点
  • 只能读到已提交的数据
  • 每次查询都会读取最新已提交版本
解决的问题
  • 避免脏读
仍然存在的问题
  • 不可重复读(Non-repeatable Read)
示例
复制代码
事务A:select balance → 100
事务B:update balance = 200; commit;
事务A:select balance → 200

同一个事务中,两次读取结果不同

可重复读(Repeatable Read)⭐

MySQL InnoDB 默认隔离级别

特点
  • 同一个事务中,多次读取同一行记录结果一致
  • 基于 MVCC(多版本并发控制)
能解决的问题
  • 脏读
  • 不可重复读
可重复读下,事务 A 提交的数据,事务 B 能看到吗?

分两种情况:

情况一:普通快照读(一致性读)
复制代码
select * from table;
  • 看不到
  • 使用事务开始时生成的 Read View
情况二:当前读(锁定读)
复制代码
select * from table for update;
select * from table lock in share mode;
  • 可以看到
  • 直接读取最新版本

这正是 MySQL 可重复读与其他数据库的核心区别之一

串行化(Serializable)

特点
  • 所有事务串行执行
  • 强制加锁(行锁 / 表锁)
实现方式
  • 一种实现方式:读操作也加行级锁
  • 完全避免并发问题
缺点
  • 并发性能极差
  • 几乎不用于高并发系统

三、可重复读真的解决了幻读吗?

什么是幻读(Phantom Read)?

复制代码
事务A:select count(*) from orders where price > 100;
事务B:insert into orders values (..., price=200); commit;
事务A:再次 select count(*) → 结果变多

多出"幻影行"

MySQL 的"特殊之处"

严格来说:

可重复读 + MVCC 并不能完全解决幻读

  • MVCC 只能保证已存在记录的版本一致
  • 对于 新插入的记录,MVCC 无能为力

MySQL 如何"防止幻读"?

方案一:锁定读(推荐)
复制代码
select * from orders where price > 100 for update;
  • 会加 Next-Key Lock(记录锁 + 间隙锁)
  • 锁住一个范围
  • 阻止其他事务插入新记录

从结果上看:幻读被避免

方案二:串行化隔离级别
  • 本质是用锁解决
  • 代价太高

四、MVCC:多版本并发控制的核心原理

MySQL 高并发性能的关键

MVCC 解决了什么问题?

  • 避免读写冲突
  • 提高并发性能
  • 实现 非阻塞读

MVCC 的核心组件

(1)隐藏字段
  • trx_id:最后一次修改该行的事务 ID

  • roll_pointer:指向 undo log

(2)Undo Log
  • 保存数据的历史版本

  • 用于事务回滚 & MVCC

(3)Read View
  • 决定"当前事务能看到哪些版本"

一致性读流程(简化)

复制代码
当前事务 → 生成 Read View
        → 判断记录 trx_id 是否可见
        → 不可见 → 通过 undo log 找历史版本

MVCC + 锁的协作关系

场景 机制
普通 select MVCC
select for updateUpdate
update / delete
防止幻读 Next-Key Lock

MVCC 解决"读一致性",锁解决"写冲突"

总结

MySQL 默认使用 可重复读隔离级别

MVCC 保证了:

  • 非阻塞读
  • 高并发性能

幻读并不是完全由 MVCC 解决

锁定读 + Next-Key Lock 才是幻读的真正终结者

MySQL 的事务模型,本质是:

MVCC + 锁机制的精妙组合

相关推荐
luoluoal2 小时前
基于python的des知识图谱的百科知识问答平台(源码+文档)
python·mysql·django·毕业设计
IT教程资源D4 小时前
[N_101]基于springboot,vue企业网盘系统
mysql·vue·前后端分离·springboot网盘
忙里偷闲学python4 小时前
mysql
linux·数据库·mysql·oracle
嘟嘟w4 小时前
MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?
数据库·mysql
四谎真好看4 小时前
MySQL 学习笔记(进阶篇3)
笔记·学习·mysql·学习笔记
星光一影4 小时前
智慧停车与充电一体化管理平台:打造城市出行新生态
mysql·vue·能源·springboot·uniapp
五阿哥永琪5 小时前
MySQL 存储引擎:特点、区别与选型原则
数据库·mysql
小无名呀5 小时前
使用C语言连接MySQL
数据库·c++·mysql
cypking5 小时前
三、NestJS 开发实战文档-->集成 MySQL(TypeORM)
前端·数据库·mysql·adb·node.js