【MySQL修炼篇】从踩坑到精通:事务隔离级别的3大异常(脏读/幻读/不可重复读)解决方案


🍃 予枫个人主页
📚 个人专栏 : 《Java 从入门到起飞》《读研码农的干货日常

💻 Debug 这个世界,Return 更好的自己!


引言

事务隔离级别是数据库面试的高频考点,也是保证数据一致性的核心基础。不少开发者在实际开发中,总会被脏读、幻读、不可重复读这三大异常问题搞得头大,尤其对MySQL默认的RR(可重复读)级别如何规避幻读一知半解。本文将从基础概念出发,逐一拆解RU、RC、RR、Serializable四种隔离级别,重点深挖RR级别解决幻读的底层逻辑,让你从理论到实操彻底吃透事务隔离级别!

文章目录

一、事务基础:ACID原则是什么?

在聊事务隔离级别之前,我们必须先明确事务的核心特性------ACID原则,这是理解隔离级别的前提👇

  • 原子性(Atomicity):事务是一个不可分割的最小单位,要么全部执行成功,要么全部执行失败回滚,不存在部分执行的情况。比如转账操作,扣款和到账必须同时成功或同时失败。
  • 一致性(Consistency):事务执行前后,数据库的数据完整性约束不会被破坏。比如转账前A和B的总余额是1000,转账后总余额依然是1000。
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行结果不会被其他事务干扰,每个事务都感觉不到其他事务在并发执行。
  • 持久性(Durability):事务执行成功后,对数据库的修改是永久性的,即使数据库发生故障,数据也不会丢失。

💡 提示:隔离性是本文的核心重点,而事务隔离级别正是为了控制隔离性的强弱,平衡并发性能和数据一致性。

二、事务并发的3大异常问题

多个事务并发执行时,如果没有合适的隔离机制,就会出现以下3种异常情况,这也是隔离级别需要解决的核心痛点🔥

2.1 脏读(Dirty Read)

  • 定义:一个事务读取到了另一个事务尚未提交的修改数据。
  • 场景示例
    1. 事务A执行转账操作,给用户B扣款100元(未提交);
    2. 事务B查询自己的余额,读取到了扣款后的余额(少了100元);
    3. 事务A因为异常回滚,扣款操作失效;
    4. 事务B读取到的"少100元"的数据就是脏数据,这就是脏读。

⚠️ 危害:脏读会导致数据判断错误,进而引发业务逻辑异常。

2.2 不可重复读(Non-Repeatable Read)

  • 定义:同一个事务内,多次读取同一批数据,结果却不一致(被其他事务修改并提交了)。
  • 场景示例
    1. 事务A第一次查询用户B的余额,结果为1000元;
    2. 事务B修改了用户B的余额为1500元,并提交事务;
    3. 事务A再次查询用户B的余额,结果变为1500元,两次读取结果不一致。

📌 注意:不可重复读的核心是"修改",同一事务内读取到了其他事务提交的修改数据。

2.3 幻读(Phantom Read)

  • 定义:同一个事务内,多次执行同一查询语句,返回的结果集行数不一致(被其他事务插入或删除并提交了)。
  • 场景示例
    1. 事务A查询余额大于500元的用户,返回2条记录;
    2. 事务B插入了一条余额600元的用户记录,并提交事务;
    3. 事务A再次执行相同的查询,返回3条记录,多了一条"幻影"数据。

✨ 关键:幻读的核心是"新增/删除",同一事务内读取到了其他事务提交的新增/删除数据,这也是最难解决的异常之一。

三、四种事务隔离级别详解

为了解决上述并发异常问题,SQL标准定义了四种事务隔离级别,从低到高依次为:Read Uncommitted(RU)、Read Committed(RC)、Repeatable Read(RR)、Serializable(串行化)。隔离级别越高,数据一致性越强,但并发性能越差。

3.1 Read Uncommitted(RU:读未提交)

  • 隔离级别:最低,允许读取其他事务未提交的数据。
  • 解决异常:不解决任何异常,会出现脏读、不可重复读、幻读。
  • 适用场景:对数据一致性要求极低,追求极致并发性能的场景(几乎不用)。
  • MySQL实操
sql 复制代码
-- 设置隔离级别为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 开启事务
START TRANSACTION;

3.2 Read Committed(RC:读已提交)

  • 隔离级别:次低,只允许读取其他事务已提交的数据。
  • 解决异常:解决脏读,会出现不可重复读、幻读。
  • 适用场景:对数据一致性有一定要求,允许不可重复读的场景(如普通业务查询)。
  • 特点:大多数数据库的默认隔离级别(如Oracle、SQL Server),但不是MySQL的。
  • MySQL实操
sql 复制代码
-- 设置隔离级别为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;

3.3 Repeatable Read(RR:可重复读)

  • 隔离级别:中高,保证同一事务内多次读取同一批数据的结果一致。
  • 解决异常 :解决脏读、不可重复读,大部分幻读(MySQL的RR级别特殊优化)。
  • 适用场景:对数据一致性要求较高,需要避免不可重复读的场景(MySQL默认隔离级别)。
  • 核心重点:MySQL RR级别如何解决大部分幻读? 🚀
    MySQL的RR级别并没有完全遵循SQL标准,而是通过MVCC(多版本并发控制)+ 间隙锁(Gap Lock) 组合机制,解决了大部分幻读问题:
    1. MVCC机制:事务开启时会生成一个一致性视图(read view),后续查询都会基于这个视图读取数据,即使其他事务插入了新数据,也不会被当前事务读取到,从而避免了大部分幻读场景。
    2. 间隙锁:当执行带有范围条件的查询(如WHERE id > 10)时,MySQL会在查询范围的间隙上添加锁,阻止其他事务在该间隙内插入数据,从根源上杜绝幻读。
  • MySQL实操
sql 复制代码
-- 设置隔离级别为可重复读(MySQL默认,可省略)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;

👍 建议:如果觉得这部分RR级别的底层逻辑讲得清晰,欢迎点赞收藏,方便后续复习!

3.4 Serializable(串行化)

  • 隔离级别:最高,强制所有事务串行执行,不允许并发。
  • 解决异常:解决脏读、不可重复读、幻读所有异常。
  • 适用场景:对数据一致性要求极高,不允许任何并发异常的场景(如金融核心交易)。
  • 缺点:并发性能极差,会导致大量事务阻塞,一般不推荐使用。
  • MySQL实操
sql 复制代码
-- 设置隔离级别为串行化
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;

四、四种隔离级别对比总结

为了方便大家快速对比和记忆,整理了以下表格👇

隔离级别 脏读 不可重复读 幻读 并发性能 适用场景
读未提交(RU) 存在 存在 存在 最高 极少使用
读已提交(RC) 不存在 存在 存在 较高 普通业务查询
可重复读(RR) 不存在 不存在 大部分解决 中等 MySQL默认,多数业务场景
串行化(Serializable) 不存在 不存在 不存在 最低 金融核心等强一致性场景

五、结尾总结

本文从事务ACID原则出发,拆解了事务并发的3大异常问题(脏读、不可重复读、幻读),详细讲解了四种事务隔离级别的特性、适用场景及MySQL实操,并重点分析了MySQL默认RR级别通过MVCC+间隙锁解决大部分幻读的底层逻辑。

核心结论:MySQL的RR级别是兼顾数据一致性和并发性能的最优选择,能满足大部分业务场景的需求;如果对一致性要求极高,可选择串行化,但需接受并发性能的损耗。

相关推荐
一起养小猫3 小时前
Flutter for OpenHarmony 实战:记账应用数据统计与可视化
开发语言·jvm·数据库·flutter·信息可视化·harmonyos
世界尽头与你3 小时前
(修复方案)CVE-2023-22047: Oracle PeopleSoft Enterprise PeopleTools 未授权访问漏洞
数据库·安全·oracle·渗透测试
韩立学长3 小时前
【开题答辩实录分享】以《智能大学宿舍管理系统的设计与实现》为例进行选题答辩实录分享
数据库·spring boot·后端
Henry Zhu1234 小时前
数据库(五):反规范化
数据库
Mr_Xuhhh4 小时前
MySQL函数详解:日期、字符串、数学及其他常用函数
java·数据库·sql
he___H5 小时前
Redis高级数据类型
数据库·redis·缓存
霖霖总总5 小时前
[小技巧60]深入解析 MySQL Online DDL:MySQL Online DDL、pt-osc 与 gh-ost 机制与最佳实践
数据库·mysql
爱学习的阿磊5 小时前
使用PyTorch构建你的第一个神经网络
jvm·数据库·python
惊讶的猫7 小时前
Redis双写一致性
数据库·redis·缓存