Mysql(四)InnoDB怎么确保RR下的数据一致性

InnoDB 在可重复读(RR) 隔离级别下,通过两大核心机制确保数据一致性:一致性读视图(Read View)Next-Key Lock 锁机制。前者解决 "不可重复读" 问题,后者解决 "幻读" 问题,两者协同保障事务内的数据视图稳定和并发操作的安全性。

一、一致性读视图(Read View):解决 "不可重复读"

"不可重复读" 指事务内多次读取同一行数据时,因其他事务修改并提交,导致前后读取结果不一致。InnoDB 通过Read View(读视图) 机制避免这一问题,核心是为每个事务创建一个 "数据快照",事务内的所有读取操作都基于这个快照,不受其他已提交事务的影响。

Read View 的工作原理:

  1. 生成时机 :事务启动时(执行第一个SELECT语句时),InnoDB 会生成一个 Read View,记录当前数据库中 "活跃事务" 的 ID 列表(即未提交的事务 ID)。

    • 每个事务启动时会分配一个唯一的递增事务 ID(trx_id)。
    • Read View 包含三个关键信息:m_low_limit_id(当前最大事务 ID+1)、m_up_limit_id(活跃事务中最小的 ID)、m_ids(活跃事务 ID 列表)。
  2. 可见性判断规则 :当事务读取某行数据时,InnoDB 会对比该行的trx_id(最后修改该行的事务 ID)与 Read View 中的信息,决定数据是否可见:

    • trx_id < m_up_limit_id:说明修改该行的事务已提交,数据可见。
    • trx_id >= m_low_limit_id:说明修改该行的事务在当前事务启动后才开始,数据不可见。
    • m_up_limit_id <= trx_id < m_low_limit_id:需检查trx_id是否在m_ids中。若在,说明事务未提交,数据不可见;若不在,说明事务已提交,数据可见。
  3. 快照的 "稳定性" :RR 级别下,Read View 一旦生成,在整个事务期间不会更新。因此,无论其他事务如何修改并提交数据,当前事务始终只能看到启动时的快照,确保 "可重复读"。

举例说明:

  • 事务 A(trx_id=100)启动,生成 Read View(此时活跃事务只有 A,m_up_limit_id=100m_low_limit_id=101)。
  • 事务 A 第一次读取stock=10(该行trx_id=50,早于 A 启动,可见)。
  • 事务 B(trx_id=200)启动,修改stock=9并提交(trx_id=200)。
  • 事务 A 再次读取stock:由于200 >= m_low_limit_id=101,事务 B 的修改对 A 不可见,A 仍读到stock=10

关于

二、Next-Key Lock:解决 "幻读"

"幻读" 指事务内两次查询同一范围的数据时,因其他事务插入新行并提交,导致第二次查询多出 "新行"。InnoDB 通过Next-Key Lock(行锁 + 间隙锁)机制防止幻读,核心是锁定 "记录本身" 和 "可能插入新记录的间隙"。

Next-Key Lock 的组成:

  1. 行锁(Record Lock) :锁定表中具体某一行记录,防止其他事务修改或删除该行。

  2. 间隙锁(Gap Lock) :锁定不存在记录的区间(间隙),防止其他事务在该区间插入新行。

Next-Key Lock = 行锁 + 间隙锁,它的锁定范围是 "左开右闭" 的区间。例如,对id=10的行加 Next-Key Lock,会锁定(上一个存在的id, 10]的区间(如(5,10],若上一个 id 是 5)。

如何防止幻读:

当事务执行带范围条件的写操作 (如UPDATE ... WHEREDELETE ... WHERE)或悲观读SELECT ... FOR UPDATE)时,InnoDB 会自动加 Next-Key Lock,既锁定符合条件的行,也锁定这些行前后的间隙,阻止新行插入。

举例说明:

  • products中存在id=5,10,15的行,库存字段stock>0

  • 事务 A 执行:SELECT * FROM products WHERE id BETWEEN 5 AND 15 FOR UPDATE(悲观读,锁定范围)。

    • InnoDB 会对id=5,10,15加行锁,同时对间隙(负无穷,5](5,10](10,15](15,正无穷)加间隙锁。
  • 事务 B 尝试插入id=7(属于(5,10]间隙):会被间隙锁阻塞,直到事务 A 提交释放锁。

  • 因此,事务 A 再次执行相同查询时,不会出现 "新插入的 id=7" 这行,避免幻读。

三、锁的持有与释放:确保事务原子性

在 RR 级别下,InnoDB 的行锁和间隙锁会持有至事务提交或回滚后才释放,而非操作完成后立即释放(RC 级别会提前释放)。这种机制保证了事务内的一系列操作(如 "查库存→扣库存→创建订单")是一个原子性的整体,中间不会被其他事务的修改打断,进一步强化了数据一致性。

总结

InnoDB 在 RR 级别下通过两大机制确保一致性:

  1. Read View:为事务创建启动时的数据快照,确保事务内多次读取结果一致,解决 "不可重复读"。
  2. Next-Key Lock:结合行锁和间隙锁,锁定记录及间隙,防止其他事务插入新行,解决 "幻读"。

这两种机制协同工作,既保证了事务隔离性,又在并发性能与数据一致性之间取得了平衡,使 RR 成为 InnoDB 的默认隔离级别,适配多数业务场景(如电商交易、金融支付)对数据准确性的高要求。

相关推荐
2301_766283441 小时前
Golang怎么实现防重复提交_Golang如何用Token机制防止表单重复提交【技巧】
jvm·数据库·python
qq_414256571 小时前
CSS如何实现元素在容器内居中_利用margin-auto技巧
jvm·数据库·python
2401_824222691 小时前
如何用 Transferable 对象零拷贝转移超大数组内存给子线程
jvm·数据库·python
SilentSamsara2 小时前
Python 并发基础:threading/GIL 与 multiprocessing 的选型逻辑
服务器·开发语言·数据库·vscode·python·pycharm
m0_495496412 小时前
如何禁用 Vite 中的热更新(HMR)以避免 React 应用加载中断
jvm·数据库·python
m0_741173332 小时前
MySQL中如何使用CAST实现类型转换_MySQL数据类型转换技巧
jvm·数据库·python
qq_413502022 小时前
如何用 bubbles 属性让自定义事件穿透多个 Web Components
jvm·数据库·python
地球资源数据云2 小时前
2015年中国30米分辨率沼泽湿地空间分布数据集
大数据·数据结构·数据库·人工智能·机器学习
2301_775639892 小时前
如何修改Oracle服务器默认的日期格式_NLS_DATE_FORMAT全局配置
jvm·数据库·python