MySQL事务ACID、隔离级别、MVCC、幻读解决

MySQL事务核心机制详解

一、事务的四大特性(ACID)

特性 英文 说明
原子性 Atomicity 事务中的操作要么全部成功,要么全部失败(通过undo log实现)
一致性 Consistency 事务执行前后,数据必须保持逻辑一致(由其他三个特性共同保障)
隔离性 Isolation 多个事务并发执行时,相互不干扰(通过锁 + MVCC实现)
持久性 Durability 事务提交后,数据永久保存(通过redo log实现)

简单记忆:原一隔持(原子、一致、隔离、持久)


二、并发事务会引发的问题

问题 说明 举例
脏读 读到其他事务未提交的数据 A转账给B,A未提交,B查账发现钱已到
不可重复读 同一事务内,两次读取同一行数据结果不一致 事务T1两次查询余额,期间T2修改了余额
幻读 同一事务内,两次查询记录数不一致 事务T1查用户列表共5条,期间T2插入1条,T1再查变6条

注意:不可重复读侧重"修改/删除",幻读侧重"新增"


三、隔离级别及解决问题

MySQL InnoDB支持四种隔离级别(由低到高):

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED(读未提交) ✔️ ✔️ ✔️
READ COMMITTED(读已提交,RC) ✔️ ✔️
REPEATABLE READ(可重复读,RR) ✔️*
SERIALIZABLE(串行化)

*注:MySQL InnoDB的RR级别通过间隙锁解决了幻读问题

设置隔离级别

sql 复制代码
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置会话级别
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 设置全局级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

四、MVCC(多版本并发控制)

1. 为什么需要MVCC?

  • 提高并发性能:读不加锁,写加锁,读写不互斥

  • 解决读写冲突 ,实现非阻塞读

2. MVCC依赖的三个隐藏字段

字段 含义
DB_TRX_ID 最近修改该行记录的事务ID
DB_ROLL_PTR 指向undo log中该行历史版本的指针
DB_ROW_ID 行ID(无主键时自动生成)

3. Read View(读视图)

RCRR隔离级别下,查询会生成Read View,用于判断哪个版本可见。

Read View包含:

  • m_ids:活跃事务ID列表

  • min_trx_id:最小活跃事务ID

  • max_trx_id:下一个待分配的事务ID

  • creator_trx_id:当前事务ID

4. 可见性判断规则

根据DB_TRX_ID与Read View对比:

  • DB_TRX_ID < min_trx_id:可见(已提交)

  • DB_TRX_ID >= max_trx_id:不可见(未来事务)

  • min_trx_id <= DB_TRX_ID < max_trx_id

    • m_ids中 → 不可见(活跃事务)

    • 不在m_ids中 → 可见(已提交)

5. RC与RR的Read View生成时机差异

隔离级别 Read View生成时机 效果
RC 每条SELECT语句都重新生成 可以读到其他事务已提交的最新修改(不可重复读)
RR 第一条SELECT时生成,整个事务复用 保证多次查询结果一致(可重复读)

五、幻读及解决方案(重点)

1. 什么是幻读?

sql

-- 事务T1

SELECT * FROM user WHERE age = 20; -- 查到2条

-- 事务T2插入一条age=20的记录并提交

SELECT * FROM user WHERE age = 20; -- 查到3条 → 幻读

2. MySQL如何解决幻读?

RR级别 下,InnoDB使用间隙锁解决幻读。

间隙锁(Gap Lock)
  • 锁定一个范围(不存在的记录位置)

  • 防止其他事务在锁定范围内插入新记录

举例说明

sql

-- 假设user表id有1, 2, 5, 8

SELECT * FROM user WHERE id BETWEEN 3 AND 7 FOR UPDATE;

-- 会锁定间隙:(2,5] 和 (5,8),不允许插入id=4或6等记录

解决幻读完整流程
  1. 事务T1执行SELECT ... WHERE条件查询

  2. InnoDB不仅对现有记录加行锁,还对查询范围加间隙锁

  3. 事务T2尝试在间隙范围内INSERT → 阻塞等待

  4. T1提交释放锁,T2才能继续 → 幻读被阻止

3. 需要注意

  • 快照读(普通SELECT,不加锁):依赖MVCC,不会加间隙锁,但RR下通过Read View也能避免幻读

  • 当前读(SELECT ... FOR UPDATE / LOCK IN SHARE MODE):依赖间隙锁防止幻读

快照读:MVCC + Read View(历史版本)

当前读:行锁 + 间隙锁(最新数据)


六、总结对比表

概念 作用 实现依赖
原子性 事务回滚 undo log
持久性 数据持久化 redo log
隔离性 并发控制 锁 + MVCC
一致性 逻辑完整性 原子+持久+隔离
MVCC 读写不互斥 隐藏字段 + undo log + Read View
幻读解决(RR) 防止新增幻影行 间隙锁(当前读)/ MVCC(快照读)

七、常见面试问题

Q1:MySQL默认隔离级别是什么?

A:REPEATABLE READ(可重复读)

Q2:RC和RR哪个性能更好?

A:RC锁范围更小,并发能力更高,但会出现不可重复读;RR保证可重复读但间隙锁可能降低并发。

Q3:MVCC完全解决了幻读吗?

A:快照读下完全解决;当前读下通过间隙锁也解决了。所以InnoDB的RR级别可以说彻底解决了幻读。

Q4:串行化级别如何工作?

A:对所有读隐式加读锁,读写完全互斥,并发最低。

相关推荐
小高学习java2 小时前
事务的边界问题,如何判断数据回滚时机。
java·数据库·后端
迷枫7122 小时前
【无标题】
数据库
TDengine (老段)3 小时前
TDengine 扫描算子 — TableScan、TagScan 与下推优化
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
放下华子我只抽RuiKe53 小时前
FastAPI 全栈后端(三):数据库与 ORM
前端·数据库·react.js·oracle·性能优化·前端框架·fastapi
BAGAE3 小时前
星链卫星数据获取:从太空安全到实时通信的技术革命
网络·数据结构·数据库·算法·云计算·hbase
zh_xuan3 小时前
Android导出并查看数据库
数据库·sqlite
加加and减减3 小时前
Docker真实安装mysql8教程并优化配置
运维·mysql·docker·容器
小短腿的代码世界4 小时前
Qt定时器高精度架构:从QTimer源码到纳秒级定时调度
数据库·qt·架构
herinspace4 小时前
管家婆辉煌软件如何新增往来单位档案分类
服务器·数据库·电脑·管家婆软件