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(读视图)

在RC 和RR隔离级别下,查询会生成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:对所有读隐式加读锁,读写完全互斥,并发最低。

相关推荐
余槐i9 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
数据库小学妹9 小时前
PostgreSQL表膨胀怎么办?autovacuum清不动的根因与排查命令
数据库·postgresql·表膨胀·mvcc·数据库运维
mister_guo9 小时前
MySQL-1267错误:排序规则冲突的原因与解决方案
数据库·mysql
骇客野人10 小时前
在麒麟操作系统上 分别安装 jdk1.8, 达梦数据库,redis ,memcache 的操作实施方案和步骤
数据库·redis·memcached
美狐美颜SDK开放平台11 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
Lost_the_wind11 小时前
MySQL学习笔记五
mysql
花间相见13 小时前
【计算基础|MySQL01】【上手】安装连接、数据类型与建库建表
数据库·后端
花间相见13 小时前
【计算基础|MySQL02】【上手】SQL 增删改查
数据库·后端
ITxiaobing202313 小时前
IP 库与 AppsFlyer 国家/地区数据不一致,如何系统地对账?
数据库·网络协议·tcp/ip
这个DBA有点耶13 小时前
从时间到语义:时序数据库与向量数据库的核心机制、选型与多模融合趋势
数据库·mysql·架构