事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过日志实现。Mysql的日志可以分为:
- binlog:server层实现
- 事务日志:包括redo log、undo log,引擎层(innodb)实现
redo log
redo log是用于备份事务中操作得到的最新数据的地方,记录数据页的物理修改。
redo log通常是物理日志,记录的是数据页的物理修改,而不是记录某一行或某几行的修改,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
在innoDB的存储引擎中,事务日志通过重做日志(redo log)和innoDB存储引擎的日志缓冲(redo Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是DBA们口中常说的“日志先行”(Write-Ahead Logging)。当事务提交之后,在Buffer Pool中映射的数据文件才会慢慢刷新到磁盘。此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。
即事务在修改数据时,innodb只修改数据的内存拷贝,然后把修改行为记录到持久在磁盘的事务日志(redo log)中,在事务日志持久化后,内存中被修改的数据在后台慢慢刷回磁盘。
即修改数据时需要写两次磁盘:
- 先将操作记录到redo log buffer,然后持久化redo log到磁盘
- 将redo log中记录的数据持久化到磁盘
为什么需要redo log(为什么采用两次写磁盘,而不直接持久化新数据?)
既然redo log是将数据持久化到磁盘上,那么必然也对应一次IO操作,那么每次修改数据直接将其刷新到磁盘的话,也是一次IO操作,按道理说效率应该一样,那么为什么还要引入redo log?
事实上,redo log写入文件尾是顺序写过程,虽然也是一次IO操作但磁头不需要移动(即事务日志采用追加的方式,因此是顺序IO)。而每次都将数据更新到磁盘其实是将 buffer pool中的数据