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

详解Innodb一次更新事物的执行过程

        InnoDB 的事务更新过程是一个精心设计的机制,确保数据的 ACID 特性(原子性、一致性、隔离性和持久性)。下面我将详细解析一次完整的事务更新过程:

1. 事务启动

  • 分配事务 ID:事务开始时,系统为事务分配一个唯一的事务 ID(trx_id)。

  • 创建 ReadView(隔离级别为 Repeatable Read 时):事务首次读操作时会生成一个 ReadView,用于判断数据的可见性(基于活跃事务列表)。

2. 执行 UPDATE 操作

2.1 定位目标数据行

  • 通过索引查找数据

    • 根据 WHERE 条件,通过聚簇索引(主键索引)或二级索引或者全表扫描找到目标数据行。

    • 如果是二级索引,需要回表到聚簇索引获取完整数据行。

2.2 加锁

  • 行级锁(X 锁)

    • 对目标数据行加 排他锁(X 锁),阻止其他事务修改或加锁。

    • 如果隔离级别是可重复读,还会对相邻的间隙加 间隙锁(Gap Lock),防止幻读。

2.3 生成 Undo Log

  • 记录旧版本数据

    • 将修改前的数据(旧版本)写入 undo log,用于事务回滚和 MVCC。

    • 数据行的隐藏字段 roll_pointer 指向 undo log 中的旧版本记录,形成版本链。

2.4 修改数据页

  • 更新 Buffer Pool

    • 在内存的 Buffer Pool 中修改数据页,生成新的数据版本。

    • 新数据行的隐藏字段 trx_id 设置为当前事务的 ID。

2.5 生成 Redo Log

  • 记录物理修改

    • 将数据页的物理修改(如页号、偏移量、修改内容)写入 redo log buffer

    • redo log 是顺序写入的物理日志,用于崩溃恢复。

3. 事务提交(COMMIT)

3.1 刷写 Redo Log

  • 保证持久性

    • 将 redo log buffer 中的日志刷盘(fsync)。

    • 通过参数 innodb_flush_log_at_trx_commit 控制刷盘策略:

      • =1:每次提交都刷盘(默认,保证持久性)。

      • =0:每秒刷盘(可能丢失 1 秒数据)。

      • =2:写入 OS 缓存,不保证立即刷盘。

3.2 释放锁

  • 行锁与间隙锁

    • 释放事务持有的所有行级锁和间隙锁。

    • 其他被阻塞的事务可以继续执行。

3.3 清理资源

  • 标记事务结束

    • 将事务状态标记为已提交,ReadView 失效(后续事务不再依赖该事务的可见性)。

    • 延迟清理 undo log(可能被其他事务的 MVCC 读操作依赖)。

3.4 写入 Binlog(可选)

  • 主从复制

    • 如果启用了二进制日志(binlog),在提交阶段通过 两阶段提交(2PC) 保证 redo log 和 binlog 的一致性。详解Mysql redo log与binlog的两阶段提交(2PC)

4. 事务回滚(ROLLBACK)

  • 反向执行 Undo Log

    • 根据 undo log 中的旧版本数据,将数据页恢复到事务开始前的状态。

  • 释放锁

    • 释放所有行锁和间隙锁。

  • 清理事务状态

    • 标记事务为已回滚,删除相关的 undo log(若无其他事务依赖)。

5. 关键机制详解

5.1 锁机制

  • 行锁(Record Lock)

    • 确保同一行数据不会被多个事务同时修改。

    • 通过 SHOW ENGINE INNODB STATUS 可查看锁信息。

  • 间隙锁(Gap Lock)

    • 可重复读隔离级别下,锁定索引范围,防止其他事务插入数据(解决幻读)。

 5.2 Redo Log 与 Undo Log

  • Redo Log

    • 物理日志,记录页的修改。

    • 顺序写入,崩溃恢复时重放未刷盘的修改。

  • Undo Log

    • 逻辑日志,记录反向 SQL(如 UPDATE 对应 DELETE)。

    • 支持事务回滚和 MVCC 的版本链。

5.3 MVCC 与版本链

  • 数据版本链

    • 每条记录的隐藏字段 trx_id 和 roll_pointer 指向 undo log 中的旧版本。

  • ReadView

    • 包含活跃事务 ID 列表(m_ids),用于判断数据版本是否可见。

    • 可见性规则

      • 如果数据行的 trx_id < 最小活跃事务 ID,则可见。

      • 如果数据行的 trx_id 在活跃事务列表中,不可见。

      • 如果数据行的 trx_id 是当前事务自身,可见。

6. 示例:一次 UPDATE 的完整流程

假设执行以下 SQL:

UPDATE user SET name = 'Alice' WHERE id = 1;
  • 事务启动

    • 分配 trx_id=100,生成 ReadView(活跃事务列表为空)。

  • 查找数据行

    • 通过主键索引找到 id=1 的数据行,当前 trx_id=90(已提交)。

  • 加锁

    • 对 id=1 的行加 X 锁,并加间隙锁(如果需要)。

  • 生成 Undo Log

    • 记录旧值 name='Bob'roll_pointer 指向该 undo log。

  • 修改数据页

    • 在 Buffer Pool 中将 name 改为 Alicetrx_id 设置为 100

  • 生成 Redo Log

    • 记录页修改的物理操作到 redo log buffer。

  • 事务提交

    • 刷写 redo log 到磁盘,释放锁,标记事务完成。

7. 性能优化点

  • 减少锁冲突

    • 使用索引优化查询条件,缩小加锁范围。

  • 合理设置隔离级别

    • 在 Read Committed 下,间隙锁较少,但可能牺牲一致性。

  • 批量提交

    • 合并多个操作为一个事务,减少 redo log 刷盘次数。

  • 调整 redo log 大小

    • 增大 innodb_log_file_size 减少刷盘频率。

http://www.xdnf.cn/news/8760.html

相关文章:

  • 使用f5-tts训练自己的模型笔记
  • 什么是总线接口
  • 基于大模型的慢性硬脑膜下血肿诊疗技术方案
  • Linux基础IO---缓冲区----文件系统----软硬链接
  • MySQL:11_事务
  • 大数据Spark(六十):Spark On Yarn 配置
  • uni-app学习笔记十--vu3 computed的运用(二)
  • Mybatis Plus 拦截器忽略机制全解:InterceptorIgnoreHelper 源码与实战
  • 免费实景三维倾斜模型数据连接分享(浙江)
  • MQTT-SpringBoot整合
  • 零残留优化!高性能电脑系统加速利器
  • 谈谈worldquant中设置的几个意思
  • 第15章—面试技巧篇(下):如何主导面试节奏和有技巧地提问面试官
  • 汽车软件刷写 APP SBL PBL概念
  • 美团2025年校招笔试真题手撕教程(一)
  • 北京航空航天大学保研上机真题
  • 四、生活常识
  • 读书感悟[2]
  • gcc编译构建流程
  • 重温简单递归
  • Es6中怎么使用class实现面向对象编程
  • Android学习之登录界面(包含忘记密码 记住密码)(java + 详细注释 + 源码)
  • 基于SpringBoot的校园电竞赛事系统
  • DARLR用于具有动态奖励的推荐系统的双智能体离线强化学习(论文大白话)
  • Java 的 synchronized
  • 【计算机网络】基于TCP进行socket编程——实现客户端到服务端远程命令行操作
  • Linux Kernel调试:强大的printk(二)
  • git子模块--命令--表格版
  • Spring MVC 的的核心原理与实践指南
  • 记录第一次正式收到SCI期刊论文的审稿