事务隔离级别选错导致数据被吞 脏读幻读一次讲透
你在开发过程中,有没有遇到过这样的情况:一个事务里查了两次同样的数据,结果居然不一样;或者查了两次同样的范围条件,结果集凭空多了一行?很多人第一反应是“是不是缓存出问题了”,但其实,更大的概率是事务隔离级别没选对。 事务隔离级别,简单来说就是决定多个事务同时运行时,彼此能看到多少对方的数据。选得太低
你在开发过程中,有没有遇到过这样的情况:一个事务里查了两次同样的数据,结果居然不一样;或者查了两次同样的范围条件,结果集凭空多了一行?很多人第一反应是“是不是缓存出问题了”,但其实,更大的概率是事务隔离级别没选对。
事务隔离级别,简单来说就是决定多个事务同时运行时,彼此能看到多少对方的数据。选得太低,数据可能被“污染”;选得太高,并发性能又会急剧下降。今天这篇文章,我们就从四个隔离级别出发,把脏读、不可重复读、幻读这三个概念,掰开揉碎讲清楚。
先搞懂四个隔离级别
SQL标准定义了四种隔离级别,从低到高依次是:
1. READ UNCOMMITTED(读未提交) ——级别最低。事务可以读取其他事务尚未提交的数据。几乎不提供任何并发控制,实际生产环境中极少见到它的身影。
2. READ COMMITTED(读已提交,简称RC) ——只能读取其他事务已经提交的数据。它成功避免了脏读,但无法避免不可重复读。
3. REPEATABLE READ(可重复读,简称RR) ——保证同一事务内多次读取同一数据,结果完全一致。这也是MySQL InnoDB的默认隔离级别。
4. SERIALIZABLE(可串行化) ——最高级别,事务完全串行执行,从根源上杜绝所有并发问题,但性能开销也是最大的。
不同隔离级别能解决的问题,可以浓缩成下面这张表:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 |
| READ COMMITTED | 避免 | 可能 | 可能 |
| REPEATABLE READ | 避免 | 避免 | InnoDB基本避免 |
| SERIALIZABLE | 避免 | 避免 | 避免 |
三种并发问题,用真实SQL讲清楚
脏读:读到别人“还没想好”的数据
脏读,指的是一个事务读取了另一个事务尚未提交的修改。如果那个事务最终回滚了,你读到的就是“脏数据”——从未真正存在过的数据。
用电商库存场景来理解:事务A开始扣减库存,把商品X的库存从100改为99,但还没提交;此时事务B查询库存,读到了99。如果事务A因支付失败回滚了,库存恢复为100,但事务B已经基于99做了后续操作——超卖了。
-- 事务A(未提交)
START TRANSACTION;
UPDATE products SET stock = stock - 1 WHERE id = 1; -- stock从100变99
-- 此时事务B读取到stock=99(未提交的数据)
-- 事务A回滚
ROLLBACK; -- stock恢复为100,但事务B已经用了99的数据
想要解决脏读,至少要把隔离级别设置为READ COMMITTED。
不可重复读:同一事务内,数据“变了”
不可重复读指的是在同一个事务内,多次读取同一数据时结果不一致。它与脏读的关键区别在于:脏读读的是未提交的数据,而不可重复读读的是已提交的数据。
用财务场景来理解:财务人员在事务A中查询员工张三的工资,第一次看到5000元;此时HR在事务B中给张三加薪至6000元并提交;事务A再次查询时,工资变成了6000元。同一个事务里两次查询结果不一样——这就是不可重复读。
-- 事务A(隔离级别READ COMMITTED)
START TRANSACTION;
SELECT salary FROM employees WHERE id = 1; -- 返回5000
-- 事务B(同时执行)
START TRANSACTION;
UPDATE employees SET salary = 6000 WHERE id = 1;
COMMIT; -- 提交修改
-- 事务A再次查询
SELECT salary FROM employees WHERE id = 1; -- 返回6000,和第一次不一样
COMMIT;
READ COMMITTED级别无法避免这个问题。你需要升级到REPEATABLE READ。
幻读:结果集“凭空多了一行”
幻读指的是在同一个事务内,多次查询某个范围的数据时,结果集的数量发生了变化——第一次查有5行,第二次查变成了6行。
打个比方:你在图书馆按分类找书,第一次看到书架上有5本书;等你转了一圈回来再数,变成了6本——多出来那本就是你不在的时候别人放上去的。
-- 事务A(隔离级别REPEATABLE READ)
START TRANSACTION;
SELECT * FROM orders WHERE status = 'pending'; -- 返回5行
-- 事务B(同时执行)
START TRANSACTION;
INSERT INTO orders (id, status) VALUES (100, 'pending');
COMMIT;
-- 事务A再次查询
SELECT * FROM orders WHERE status = 'pending'; -- 返回6行,多了一行!
COMMIT;
MySQL的RR为什么能“基本避免”幻读?
按照SQL标准,REPEATABLE READ级别实际上是允许幻读的。但MySQL InnoDB通过MVCC(多版本并发控制)+ Gap Lock(间隙锁) 的组合拳,在绝大多数场景下实实在在地避免了幻读的发生。
- MVCC:事务开始时拍一次快照,后续的普通SELECT都基于这个快照来读,别人提交了新数据你也看不到。
- Gap Lock(间隙锁):锁定索引记录之间的空隙,阻止其他事务在范围内插入新行。
但有一点需要特别留意:DML语句(UPDATE/DELETE)不遵循快照读,它们可能会看到其他事务刚提交的行。所以在某些边缘场景下,RR级别仍然有可能出现幻读。
MySQL vs PostgreSQL:默认隔离级别为什么不同?
这是一个容易被忽略,但非常重要的差异。
- MySQL InnoDB默认使用REPEATABLE READ(RR)
- PostgreSQL默认使用READ COMMITTED(RC)
为什么?答案在于两者MVCC的实现机制不同:
| 对比维度 | MySQL InnoDB(RR) | PostgreSQL(RC) |
|---|---|---|
| 快照时机 | 事务开始时拍一次快照 | 每条SELECT重新生成快照 |
| 不可重复读 | 避免 | RC级别会出现 |
| 幻读 | 基本避免(MVCC+间隙锁) | RC级别会出现 |
| 适用场景 | 高并发CRUD | 复杂查询、数据分析 |
MySQL选择RR作为默认级别,是为了在并发性能和数据一致性之间取得一个较好的平衡,适合绝大多数互联网业务场景。PostgreSQL选择RC作为默认,则是因为它在RR级别下对幻读的处理更加严格,反而可能导致更多的死锁问题。
业务场景中怎么选隔离级别?
| 业务场景 | 推荐级别 | 理由 |
|---|---|---|
| 金融账务、库存扣减 | SERIALIZABLE 或 RR | 数据一致性要求极高,不容有失 |
| 电商订单、用户中心 | RR(MySQL默认) | 平衡性能与一致性,典型适用场景 |
| 报表查询、数据分析 | RC | 以查询为主,可接受不可重复读 |
| 高并发日志写入 | RC 或 READ UNCOMMITTED | 写入为主,对一致性要求低 |
一条核心的选型原则是:不是隔离级别越高就越好。隔离级别越高,并发性能越低。你需要根据业务对一致性和性能的实际要求来做权衡。
实战避坑:两个常见的隔离级别陷阱
陷阱1:在RC级别下做“先查后改”
很多业务逻辑都是“先查询状态,再根据状态做更新”。在RC级别下,两次查询之间数据可能被其他事务修改,导致“查的时候是A,改的时候已经变成B了”——数据就这样被“吞”掉了。解决方案:要么使用RR级别,要么在查询时加上FOR UPDATE把数据锁住。
陷阱2:RR级别下的间隙锁导致死锁
RR级别通过间隙锁成功避免了幻读,但间隙锁本身也是死锁的常见来源。在RR级别下做范围删除或范围更新,很可能锁住大量不存在的“间隙”,导致多个事务互相等待,最终形成死锁。如果你的业务场景不需要防止幻读,不妨考虑降级到RC级别,牺牲一点一致性来换取更高的并发性能。
总结
事务隔离级别是数据库并发控制的核心机制,直接影响数据的正确性和系统的吞吐量。透彻理解脏读、不可重复读、幻读的本质差异,搞清楚MySQL为什么选择RR、PostgreSQL为什么选择RC作为默认值,你就能在实际业务场景中做出更合理的选择,写出更可靠、更高效的事务代码。
你是一名 AI 行业编辑,请围绕下面这条热点输出一份资讯解读:
热点:事务隔离级别选错导致数据被吞 脏读幻读一次讲透要求:
1. 先用一句话解释这条热点在讲什么
2. 再总结它为什么重要
3. 说明会影响哪些 AI 产品或内容方向
4. 最后给出 3 个适合资讯站使用的标题
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
相关热点面壁智能聚焦端侧AI,不拼参数大小,而是通过知识密度提升与模型风洞技术,将大模型压缩至手机、汽车等设备。其MiniCPM以2B参数超越同期8B对手。CTO曾国洋22岁主导训练中国首个大语言模型CPM-1。端侧AI追求“默契系统”,在用户开口前预判需求,已在吉利、上汽大众等车型落地应用。
印度IT巨头HCLTech投资最高350亿卢比建设AI数据中心,容量可扩展至50MW,提供从设计到运营的端到端服务,旨在满足政府及企业日益增长的算力需求,抢占印度快速增长的数据中心市场,并推动AI基础设施布局。
小米具身机器人在汽车工厂自攻螺母上件工站实现双侧作业成功率98%,接近人工水平。同时在新工站分别达到90%成功率,从单一操作拓展至多工站协同,验证了具身智能在复杂工业环境的落地能力。
全球AI行业正迎来新的财富格局,DeepSeek创始人梁文锋凭借其公司的迅猛发展,个人财富急剧膨胀,一举超越多位硅谷知名人物,成为全球AI公司领域的新首富。以下将详细解析其身价飙升背后的关键因素及公司发展历程。 一、身价飙升至360亿美元,超越多位AI大佬 根据最新彭博亿万富豪指数,DeepSeek
- 日榜
- 周榜
- 月榜
热点快看
