MVCC(多版本并发控制)

在MySQL的InnoDB存储引擎中,REPEATABLE READ 隔离级别通过 MVCC(多版本并发控制)Next-Key Lock(记录锁 + 间隙锁) 来实现事务的隔离性,尤其是避免 幻读(Phantom Read) 问题。下面详细解释这两种机制的作用及其如何避免幻读。


1. MVCC(多版本并发控制)

MVCC 是 InnoDB 实现高并发的重要机制,它通过保存数据的多个版本来实现非阻塞读操作。

MVCC 的核心思想
  • 每个事务在开始时会被分配一个唯一的事务ID(transaction_id)。

  • 每条记录会保存两个隐藏字段:

    • DB_TRX_ID:记录最后一次修改它的事务ID。

    • DB_ROLL_PTR:指向回滚段中的 undo log,用于重建旧版本数据。

  • 事务在读取数据时,只能看到以下数据:

    • 事务开始之前已经提交的数据。

    • 当前事务自身修改的数据。

MVCC 如何避免幻读
  • REPEATABLE READ 隔离级别下,事务在第一次读取数据时会生成一个 一致性视图(Consistent View)

  • 后续的所有读操作都基于这个一致性视图,即使其他事务插入或删除了数据,当前事务也不会看到这些变化。

  • 因此,MVCC 可以避免 不可重复读幻读


2. Next-Key Lock(记录锁 + 间隙锁)

Next-Key Lock 是 InnoDB 在 REPEATABLE READ 隔离级别下使用的一种锁机制,它结合了 记录锁(Record Lock)间隙锁(Gap Lock)

Next-Key Lock 的作用
  • 记录锁(Record Lock):锁定索引记录。

  • 间隙锁(Gap Lock):锁定索引记录之间的间隙,防止其他事务在间隙中插入新记录。

  • Next-Key Lock:锁定记录及其前后的间隙。

Next-Key Lock 如何避免幻读
  • 当执行范围查询时,InnoDB 会对查询范围内的所有记录和间隙加锁。

  • 例如,执行以下查询:

    sql

    复制

    复制代码
    SELECT * FROM users WHERE age > 20 AND age < 30 FOR UPDATE;

    InnoDB 会对 age > 20 AND age < 30 范围内的所有记录和间隙加锁,防止其他事务插入满足条件的新记录。

  • 这样,即使其他事务尝试插入 age = 25 的新记录,也会被阻塞,从而避免幻读。


3. MVCC 和 Next-Key Lock 的协同作用

  • MVCC

    • 提供一致性视图,确保事务在读取数据时看到的是稳定的快照。

    • 避免 不可重复读 和部分 幻读

  • Next-Key Lock

    • 锁定记录和间隙,防止其他事务插入新记录。

    • 完全避免 幻读

示例

假设有一个表 users,数据如下:

id age
1 20
2 25
3 30
  • 事务1

    sql

    复制

    复制代码
    START TRANSACTION;
    SELECT * FROM users WHERE age > 20 AND age < 30 FOR UPDATE;
    • InnoDB 会对 age = 25 的记录加锁,并对 (20, 25)(25, 30) 的间隙加锁。
  • 事务2

    sql

    复制

    复制代码
    START TRANSACTION;
    INSERT INTO users (id, age) VALUES (4, 22); -- 阻塞,因为 age = 22 在 (20, 25) 的间隙中
    • 由于间隙锁的存在,事务2的插入操作会被阻塞,从而避免幻读。

4. 为什么 REPEATABLE READ 能避免幻读?

  • MVCC 确保事务在读取数据时看到的是稳定的快照,避免了 不可重复读

  • Next-Key Lock 锁定记录和间隙,防止其他事务插入新记录,避免了 幻读


5. 总结

  • REPEATABLE READ 隔离级别通过 MVCCNext-Key Lock 协同工作,实现了高并发下的数据一致性。

  • MVCC 提供一致性视图,避免不可重复读。

  • Next-Key Lock 锁定记录和间隙,完全避免幻读。

  • 这种机制在保证数据一致性的同时,提供了较高的并发性能,是 MySQL 默认的隔离级别。

相关推荐
睡觉的时候不会困3 小时前
Redis 主从复制详解:原理、配置与主从切换实战
数据库·redis·bootstrap
程序员的世界你不懂4 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
自学也学好编程4 小时前
【数据库】Redis详解:内存数据库与缓存之王
数据库·redis
JAVA不会写5 小时前
在Mybatis plus中如何使用自定义Sql
数据库·sql
IT 小阿姨(数据库)5 小时前
PgSQL监控死元组和自动清理状态的SQL语句执行报错ERROR: division by zero原因分析和解决方法
linux·运维·数据库·sql·postgresql·centos
ChinaRainbowSea6 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程
小马学嵌入式~7 小时前
嵌入式 SQLite 数据库开发笔记
linux·c语言·数据库·笔记·sql·学习·sqlite
Java小白程序员7 小时前
MyBatis基础到高级实践:全方位指南(中)
数据库·mybatis
Monly217 小时前
人大金仓:merge sql error, dbType null, druid-1.2.20
数据库·sql
不宕机的小马达7 小时前
【Mysql|第一篇】Mysql的安装与卸载、Navicat工具的使用
数据库·mysql