image.png

(1) 更新数据阶段

  • Buffer Pool 缓冲池
    • 内存结构;
    • 更新语句时,比如 id=1 这行数据,先看看是否在缓冲池里,如果不在,会直接从磁盘里加载到缓冲池里来,而且还会对这行数据加独占锁;
  • undo 日志文件
    • 为了允许在事务提交前,可以对数据进行回滚,会把更新前的值写入 undo 日志文件;
    • 例如,id=1 这样数据的 name=zhangsan,更新为 name=xxx,那么会把原先 id=10 and name=zhangsan 这些信息,写入到 undo 日志文件中去;
  • 执行器更新内存数据
    • 更新的时候,先更新缓冲池中的数据,因为与磁盘中的数据不一致了,内存更新后的数据称为脏数据;
  • Redo Log Buffer

    • 内存结构;
    • redo 日志,记录对数据做了什么修改,比如 id=1 这行数据更新成了name字段值为xxx;
    • redo 日志,在 MySQL 突然宕机的时候,用来恢复你更新过的数据,避免数据丢失; :::info 如果还没提交事务,MySQL 宕机了怎么办?
  • 内存中 Buffer Pool 修改过的数据都丢失掉,内存中 Redo Log Buffer 的 redo 日志也会丢失;

  • 此时宕机,内存中丢失的数据是不要紧的,磁盘还是更新前的值,只是这个事务的执行失败了,没有更新成功,应用系统会收到一个数据库的异常;
  • 宕机不会有任何问题,只有应用收到一个异常; :::

(2) 提交事务阶段

  • 提交事务的时候,将 redo 日志写入磁盘中
    • 刷盘策略:innodb_flush_log_at_trx_commit 参数
      • 0:事务提交时,不把 redo log 刷入磁盘;
      • 1(建议):事务提交时,必须把 redo log 从内存刷入磁盘,只要事务提交成功, redo log 必然在磁盘里了;
        • 如果 buffer pool 更新过的数据还没同步到磁盘里,哪怕此时宕机了,重启后,也可以根据 redo 日志去恢复内存之前做过的修改;
      • 2:事务提交时,把 redo log 写入磁盘对应的 os cache 内存缓存里;
  • 提交事务的时候,将 binlog 日志写入磁盘中
    • binlog:
      • binlog 归档日志,偏向于逻辑性的日志,例如对 users 表中的 id=10 的行数据做了更新操作,更新以后的值是什么;而 redo log 是偏向于物理性的重做日志,例如对哪个数据页中的什么记录,做了什么修改;
      • binlog 不是 InnoDB 存储引擎特有的日志文件,是属于 mysql server 自己的日志文件;而 redo log 是属于 InnoDB 特有的一个东西;
    • 刷盘策略:sync_binlog 参数
      • 0:默认值,提交事务时,把 binlog 写入磁盘对应的 os cache 内存缓存里;
      • 1:提交事务时,强制把 binlog 直接写入到磁盘文件里;
  • 基于 binlog 和 redo log 完成事务的提交
    • 将本次更新对应的 binlog 文件名称和对应的文件里的位置,都写入 redo log 日志文件里;
    • 同时,在 redo log 日志文件里写入一个 commit 标记,完成最终的事务提交;
      • commit 标记的意思在于,判定此次事务是否成功;
  • 事务已经提交,后台 IO 线程随机将内存更新后的脏数据输入磁盘
    • 此时事务已提交,redo log 和 binlog 都记录了修改的内存“id=10 的这样数据,name 值更新为 xxx”;
    • MySQL 有一个后台 IO 线程,会在之后的某个时间里,随机把内存 buffer pool 中的修改后的脏数据刷入磁盘文件;
      • 如果脏数据刷入磁盘前,发生宕机也没关系,重启后,会根据 redo 日志恢复之前提交事务做过的修改到内存里去,就是 id=10 的数据 name 值修改为 xxx,然后等某个时候,IO 线程再把脏数据刷入磁盘;

(3) 总结 InnoDB 存储引擎的架构原理

  • InnoDB 存储引擎主要包含:
    • buffer pool、redo log 等内存里的缓存数据;
    • undo 日志文件、redo 日志文件、binlog 日志文件(所属 mysql server);
    • 执行更新时,每条 SQL 都会对应修改 buffer pool 里的缓存数据,写 undo 日志、写 redo log buffer 几个步骤;
    • 提交事务时,会把 redo log、binlog 刷入磁盘,完成 redo log 中的事务 commit 标记;
    • 最后,后台 IO 线程会随机的把 buffer pool 里的脏数据刷入磁盘;