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

详解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 减少刷盘频率。

相关文章:

  • 【概率论基本概念02】最大似然性
  • 【MySQL成神之路】MySQL函数总结
  • 【C语言干货】free细节
  • RocketMQ 索引文件(IndexFile)详解:结构、原理与源码剖析
  • 用 Python 实现了哪些办公自动化
  • 力扣第157场双周赛
  • 湖北理元理律师事务所债务优化方案:让还款与生活平衡的艺术
  • 基于PyTorch的残差网络图像分类实现指南
  • SGMD辛几何模态分解
  • 【MATLAB代码】主动声纳多路径目标测距与定位,测距使用互相关,频率、采样率可调、声速可调,定位使用三边法|订阅专栏后可直接查看源代码
  • 第一章 半导体基础知识
  • 华为OD机试真题——出租车计费/靠谱的车 (2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
  • 网络安全--PHP第二天
  • 华为OD机试真题——启动多任务排序(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳实现
  • Qt for Android 安卓低功耗蓝牙(BLE)开发环境搭建
  • JavaWeb:SpringBoot工作原理详解
  • 【第五篇】 SpringBoot中的高级配置
  • 可编程幻彩LED灯条的设计
  • 3d世界坐标系转屏幕坐标系
  • 详解3DGS
  • 做推送的网站除了秀米还有/如何自己做一个网址
  • 深圳效果好的免费网站建设/seo资料网
  • 做网站是什么鬼/高级搜索入口
  • 网站建设的需求怎么写/国内新闻
  • 宁波建站模板厂家/鹤岗网站seo
  • 邢台做网站咨询/怎样制作网页新手自学入门