本文参考 Java元宇宙
InnoDB数据操作
BufferPool
我们都知道,Mysql数据库的数据存在磁盘上,但磁盘IO读写是十分耗时的操作,如果每一次增删改查都直接操作磁盘数据,那数据库真成🐢了
显然Mysql也不会这么做,它引入了一个内存组件BufferPool
,它会缓存磁盘中读取的记录和索引,在这里进行对数据做修改。
事务回滚
现在我们执行了一条 update user set name='zhangsan' where id = 1;
操作,如果我们想回滚,但这时BufferPool
已经写入了数据,怎么办?别担心,InnoDB提供的undo log
来帮你!
Mysql在更新记录前,会先先把这行数据写入undo log
中,再修改BufferPool
的数据,这样需要回滚时就可以从undo log
中获取记录的旧值
看下insert语句下undo log
的样子:
关于回滚操作:
- 在缓存页里执行insert语句,那么在undo log日志里,对这个操作记录的回滚日志就有一个主键和一个对应的delete操作,能让这次insert操作回退
- 执行的是delete语句,那么要把删除的那条数据记录下来,执行insert操作把那条数据插入回去
- 执行的是update语句,那么要把更新之前的那个值记录下来,回滚的时候重新update,把之前更新前的旧值更新回去
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,就不怕数据库突然宕机了!
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 标记。这样一个事务才算是真正提交了。
三种日志对比
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,可以用来进行数据库的恢复及复制。
- 执行顺序:
异步刷盘
事务提交之后,MySQL会开一个后台线程,不断把BufferPool里的脏数据刷回磁盘中。
那刷盘的时候怎么知道哪些是脏数据呢?
Buffer Pool会有一个Flush List记录要刷回磁盘的脏数据!
参考:
Q.E.D.