本文参考 Java元宇宙

InnoDB数据操作

BufferPool

我们都知道,Mysql数据库的数据存在磁盘上,但磁盘IO读写是十分耗时的操作,如果每一次增删改查都直接操作磁盘数据,那数据库真成🐢了

显然Mysql也不会这么做,它引入了一个内存组件BufferPool,它会缓存磁盘中读取的记录和索引,在这里进行对数据做修改。
image-20211217210608540

事务回滚

现在我们执行了一条 update user set name='zhangsan' where id = 1;操作,如果我们想回滚,但这时BufferPool已经写入了数据,怎么办?别担心,InnoDB提供的undo log 来帮你!

Mysql在更新记录前,会先先把这行数据写入undo log中,再修改BufferPool的数据,这样需要回滚时就可以从undo log中获取记录的旧值

看下insert语句下undo log的样子:
image-20211217211748379

关于回滚操作:

  • 在缓存页里执行insert语句,那么在undo log日志里,对这个操作记录的回滚日志就有一个主键和一个对应的delete操作,能让这次insert操作回退
  • 执行的是delete语句,那么要把删除的那条数据记录下来,执行insert操作把那条数据插入回去
  • 执行的是update语句,那么要把更新之前的那个值记录下来,回滚的时候重新update,把之前更新前的旧值更新回去

image-20211217212317418

redo log

这是InnoDB提供的另一种恢复日志,负责前滚恢复,对 Buffer Pool 中的数据执行完更新操作之后,要把这个更新操作写入到 redo log buffer 中。

redo log buffer 中的数据是否写入磁盘由innodb_flush_log_at_trx_commit这个参数控制:

  • 0 提交事务,不会将 redo log buffer 的数据输入磁盘
  • 1 提交事务,保证会将 redo log buffer 的数据输入磁盘(立即)
  • 2 提交事务,会将 redo log buffer 的数据先输入到 os cache

有了redo log,就不怕数据库突然宕机了!
image-20211217213644586

bin log

这个是Mysql Server提供的日志,在提交日志时会写入bin log

和redo log一样,是否写回磁盘由参数sync_binlog控制:

  • 0 提交事务,先将 bin log 数据写入到 os cache 中,由 os cache 机制自己刷盘
  • 1 提交事务,保证将 bin log 数据输入到 bin log 中

写入 redo log 和 bin log 之后,会将本次更新对应的 binlog 文件名称和地址,都写入到 redo log 中,同时在 redo log 里面加上一个 commit 标记。这样一个事务才算是真正提交了。

image-20211217213845810

三种日志对比

undo log、redo log、bin log区别:

  • redo log中记录的是要更新的数据,比如一条数据已提交成功,并不会立即同步到磁盘,而是先记录到redo log中,等待合适的时机再刷盘,为了实现事务的持久性
  • undo log中记录的是当前操作中的相反操作,一条insert语句在undo log中会对应一条delete语句,update语句会在undo log中对应相反的update语句,在事务回滚时会用到undo log,实现事务的原子性,同时会用在MVCC中,undo中会有一条记录的多个版本,用在快照读中;
  • bin log中记录的是整个mysql数据库的操作内容,对所有的引擎都适用,包括执行的DDL、DML,可以用来进行数据库的恢复及复制。
  • 执行顺序:
    image-20211217214114243

异步刷盘

事务提交之后,MySQL会开一个后台线程,不断把BufferPool里的脏数据刷回磁盘中。

那刷盘的时候怎么知道哪些是脏数据呢?

Buffer Pool会有一个Flush List记录要刷回磁盘的脏数据!

image-20211217214838649

参考:

  1. 北漂程序员
  2. Java元宇宙

Q.E.D.


记录 • 分享 • 日常