当前位置: 首页 > news >正文

什么是脏读、幻读、不可重复读?

脏读、幻读和不可重复读是数据库事务隔离级别中常见的三种数据一致性问题。它们描述了在并发事务环境下可能出现的异常现象。下面通过对比表格和具体示例进行清晰解析:


核心概念对比表

问题类型触发场景本质原因示例
脏读 (Dirty Read)事务A读取了事务B未提交的修改读取到其他事务的中间状态(可能被回滚的数据)事务B修改数据未提交 → 事务A读取 → 事务B回滚 → 事务A读到"脏数据"
不可重复读 (Non-Repeatable Read)同一事务内多次读取同一数据,结果不一致其他事务修改或删除了该数据事务A第一次读取 → 事务B修改数据并提交 → 事务A再次读取 → 两次结果不同
幻读 (Phantom Read)同一事务内多次范围查询,结果集数量变化其他事务新增或删除了范围内的数据事务A查询年龄>30有5人 → 事务B新增1个>30记录 → 事务A再查变6人

详细解析与示例

一、脏读(Dirty Read)
  • 定义:事务A读取了事务B尚未提交的修改,若事务B最终回滚,则事务A读取的是无效的"脏数据"。
  • 示例
    -- 事务B(未提交)
    UPDATE accounts SET balance = 1000 WHERE id = 1;  -- 原值500-- 事务A(读取未提交数据)
    SELECT balance FROM accounts WHERE id = 1; -- 读到1000(脏数据!)-- 事务B回滚
    ROLLBACK;  -- balance恢复为500
    

    📌 风险:事务A基于错误数据(1000)进行了错误操作。

二、不可重复读(Non-Repeatable Read)
  • 定义:同一事务内多次读取同一数据,由于其他事务的修改或删除操作,导致读取结果不一致。
  • 示例
    -- 事务A
    SELECT balance FROM accounts WHERE id = 1; -- 第一次读:500-- 事务B提交修改
    UPDATE accounts SET balance = 800 WHERE id = 1;
    COMMIT;-- 事务A再次读取
    SELECT balance FROM accounts WHERE id = 1; -- 第二次读:800(结果改变!)
    

    📌 影响:事务A无法保证多次读取的一致性(如校验数据时结果突变)。

三、幻读(Phantom Read)
  • 定义:同一事务内多次执行范围查询,由于其他事务新增或删除数据,导致结果集数量变化(如"凭空出现"新记录)。
  • 示例
    -- 事务A:查询年龄>30的员工
    SELECT * FROM employees WHERE age > 30; -- 返回5条记录-- 事务B新增并提交
    INSERT INTO employees (name, age) VALUES ('Bob', 35);
    COMMIT;-- 事务A再次查询
    SELECT * FROM employees WHERE age > 30; -- 返回6条记录(多出Bob!)
    

    📌 关键区别:幻读关注结果集数量变化(增删导致),不可重复读关注单条数据的值变化


隔离级别如何解决这些问题?

数据库通过四种隔离级别控制并发问题:

隔离级别脏读不可重复读幻读性能
READ UNCOMMITTED (读未提交)最高
READ COMMITTED (读已提交)
REPEATABLE READ (可重复读)❌*中等
SERIALIZABLE (串行化)最低

💡 说明:

  • ✅ = 可避免该问题
  • ❌ = 无法避免
  • ❌* = MySQL的InnoDB引擎通过 MVCC(多版本并发控制) 解决了幻读,但部分数据库(如SQL Server)仍需串行化才能避免。

技术原理剖析

  1. 读已提交(READ COMMITTED)

    • 通过 语句级快照:每次查询只读取已提交的数据。
    • 解决脏读,但无法避免不可重复读和幻读。
  2. 可重复读(REPEATABLE READ)

    • 通过 事务级快照(MVCC):事务首次查询建立数据快照,后续读取均基于此版本。
    • 解决脏读和不可重复读。
    • MySQL如何解决幻读
      • 使用 Next-Key Locking(间隙锁+记录锁)锁定查询范围,阻止其他事务插入(能解决大部分的幻读问题,但是并不能完全解决幻读)。
  3. 串行化(SERIALIZABLE)

    • 通过 完全加锁:所有操作串行执行,牺牲并发性换取一致性。
    • 解决脏读、不可重复读和幻读。

实际开发建议

在这里插入图片描述

  • 优先选择 READ COMMITTED:平衡性能与一致性(多数场景适用)。
  • 关键业务用 REPEATABLE READ:如账户余额计算。
  • 极少用 SERIALIZABLE:除非绝对要求数据完美一致(如银行清算系统)。

⚠️ 注意:不同数据库实现有差异(如Oracle默认READ COMMITTED,MySQL默认REPEATABLE READ)。

http://www.dtcms.com/a/330245.html

相关文章:

  • linux编程----文件(framebuffer)
  • 正则表达式解析(三)
  • 方法论基础。
  • 与Deepseek对话了解无线电通信知识
  • 自动曝光算法参考
  • Linux Framebuffer(帧缓冲)与基本 UI 绘制技术
  • GitHub宕机时的协作方案
  • 力扣 hot100 Day72
  • Transformer开端
  • 有效涂色问题-二维dp
  • C++进阶之lambda三种回调方式性能差异(四百二十七)
  • 【13】Transformers快速入门:Transformers 分词器 (Tokenizer) 实战?
  • 哈希表之两个数组的交集(leetcode349)
  • 智能合约开发全流程实战指南
  • 【LeetCode】4. 寻找两个正序数组的中位数
  • 芯伯乐300kHz降压DC/DC转换器XBL4005:4.5V~40V宽电压范围,5A大电流高效输出
  • 三伍微电子GSR2406 IoT FEM 2.4G PA 射频前端模组芯片
  • 深入解析C语言嵌套结构体的内存管理与操作实践
  • linux_网络层-ip协议
  • [系统架构设计师]信息安全技术基础知识(三)
  • SpringBoot3+ Elasticsearch8 Spring-data-Elasticsearch使用
  • 多模态数据集分级方案设计与实现
  • 容器基础镜像制作
  • ETLCloud批流一体化体现在哪
  • 【Python】Python 函数基本介绍(详细版)​
  • 版图设计学习2_掌握PDK中的层定义(工艺文档精读)
  • DAY39打卡
  • 【运维进阶】管理变量和事实
  • 哥斯拉--安装、使用
  • graf示教界面技术累积