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

InnoDB如何解决脏读、不可重复读和幻读的?

InnoDB 引擎通过 MVCC(多版本并发控制)Next-Key Locking(临键锁) 两大核心机制解决脏读、不可重复读和幻读问题,具体实现原理如下:


一、解决脏读:MVCC 的 ReadView 机制

原理
事务只能读取已提交的数据版本(通过 Undo Log 构建历史版本)。
在这里插入图片描述

示例

  • 事务B修改数据(未提交) → 生成新版本(DB_TRX_ID = 100)
  • 事务A(ID=50)查询:
    • DB_TRX_ID=100 > 50 → 从Undo Log读取修改前的版本
    • 避免读取未提交的脏数据

隔离级别支持
READ COMMITTED(读已提交)及以上级别自动启用。


二、解决不可重复读:一致性快照(Consistent Read)

原理
在 REPEATABLE READ 级别,事务首次查询时创建 ReadView(快照),后续所有读取均基于此快照版本。
在这里插入图片描述

示例

  1. 事务A(ID=60)首次读取 balance=500
  2. 事务B(ID=70)修改 balance=800 并提交
  3. 事务A再次读取:
    • 检查DB_TRX_ID=70(不在事务A的ReadView活跃列表中)
    • 但事务A使用快照读 → 仍返回 balance=500

隔离级别支持
REPEATABLE READ(可重复读)级别生效。


三、解决幻读:Next-Key Locking(临键锁)

原理
MVCC 无法阻止其他事务插入新数据,因此 InnoDB 通过 临键锁 = 记录锁(Record Lock) + 间隙锁(Gap Lock) 锁定范围:

  • 记录锁:锁定索引记录
  • 间隙锁:锁定索引记录之间的范围(阻止插入)
    在这里插入图片描述

示例

-- 事务A:范围查询(加临键锁)
SELECT * FROM users WHERE age > 30 FOR UPDATE; 
-- 锁定现存age>30的记录 + 间隙(30, +∞)-- 事务B:尝试插入
INSERT INTO users (age) VALUES (35); -- 被阻塞!

隔离级别支持
REPEATABLE READ 级别自动启用临键锁。


四、InnoDB 解决方案总结表

问题解决机制技术实现触发条件
脏读MVCC 多版本读通过 Undo Log 读取已提交版本READ COMMITTED 及以上
不可重复读一致性快照(ReadView)事务内所有读操作基于首次快照REPEATABLE READ 级别
幻读Next-Key Locking记录锁 + 间隙锁锁定范围REPEATABLE READ + 写操作或显式锁

五、不同隔离级别的行为对比

操作READ COMMITTEDREPEATABLE READ
普通SELECT总是读最新已提交数据读事务开始时的快照
加锁SELECT(FOR UPDATE)仅加记录锁加临键锁(记录锁+间隙锁)
幻读风险可能发生完全避免

六、实战验证方案

1. 查看当前隔离级别
SELECT @@transaction_isolation; -- MySQL 8.0+
2. 测试不可重复读(REPEATABLE READ 下)
-- 事务A
START TRANSACTION;
SELECT balance FROM accounts WHERE id=1; -- 返回500-- 事务B(提交修改)
UPDATE accounts SET balance=800 WHERE id=1;
COMMIT;-- 事务A再次查询(仍返回500)
SELECT balance FROM accounts WHERE id=1; 
COMMIT;
3. 测试幻读防护
-- 事务A(加锁查询)
START TRANSACTION;
SELECT * FROM users WHERE age>30 FOR UPDATE; -- 锁住范围-- 事务B(尝试插入)
INSERT INTO users (name, age) VALUES ('Bob',35); -- 阻塞直到超时!

七、注意事项

  1. 写操作仍使用最新数据
    UPDATE/DELETE 总是基于最新提交数据(即使 REPEATABLE READ 级别)。

    -- 事务A
    SELECT * FROM accounts; -- 快照读:返回旧数据
    UPDATE accounts SET balance=balance+100; -- 更新基于最新数据!
    
  2. 显式加锁跳过 MVCC
    SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE 直接读取最新数据并加锁。

  3. 间隙锁的代价

    • 可能引发死锁(如两个事务互相等待对方间隙)
    • 可通过 innodb_locks_unsafe_for_binlog=ON 禁用(不推荐)

💡 最佳实践

  • 默认使用 REPEATABLE READ(InnoDB 的默认隔离级别)
  • 范围查询后立即操作数据时,显式加锁(FOR UPDATE
  • 写密集型场景监控锁竞争:SHOW ENGINE INNODB STATUS

InnoDB 通过 MVCC 和 Next-Key Locking 的精妙配合,在保证高并发的同时实现了数据强一致性,成为其作为事务型存储引擎的核心竞争力。

http://www.lryc.cn/news/620011.html

相关文章:

  • mysql - 查询重复数据,不区分大小重复问题解决
  • 服务器查看 GPU 占用情况的方法
  • 安全点(Safepoint)完成后唤醒暂停线程的过程
  • 响应式对象的类型及其使用场景
  • 量子安全新纪元:F5发布全新AI驱动的全栈式后量子加密AI安全方案
  • 破解测试数据困境:5招兼顾安全与真实性
  • 全球AI安全防护迈入新阶段:F5推出全新AI驱动型应用AI安全解决方案
  • 【前端Vue】使用ElementUI实现表单中可选择可编辑的下拉框
  • 仓库无人叉车的安全功能有哪些?如何在提升效率时保障安全?
  • k8s中的控制器的使用
  • 汽车高位制动灯难达 CIE 标准?OAS 光学软件高效优化破局
  • 中科米堆CASAIM汽车零部件三维扫描检测解决方案
  • 服务器通过生成公钥和私钥安全登录
  • 单例模式的理解
  • Spring Security 前后端分离场景下的会话并发管理
  • C语言:指针(4)
  • 【2025】Datawhale AI夏令营-多模态RAG-Task3笔记-解决方案进阶
  • 蓝蜂网关在雄安新区物联网建设中的关键应用
  • 补环境基础(四) Hook插件
  • Spring Boot项目调用第三方接口的三种方式比较
  • 当img占不满div时,图片居中显示,两侧加当前图片模糊效果
  • 如何记录日常笔记?
  • 【Linux学习|黑马笔记|Day3】root用户、查看权限控制信息、chmod、chown、快捷键、软件安装、systemctl、软连接、日期与时区
  • 语音交互像聊天:声网RTC技术给AI客服加温度
  • 基于 MybatisPlus 将百度天气数据存储至 PostgreSQL 数据库的实践
  • 开发避坑指南(25):MySQL不支持带有limit语句的子查询的解决方案
  • Java研学-RabbitMQ(六)
  • 算法题详细解析 + 代码 + 注释
  • 在 uniapp 里使用 unocss,vue3 + vite 项目
  • 数据结构初阶(12)排序算法—插入排序(插入、希尔)(动图演示)