在MySQL中,数据以页的形式存放。
redo log
为了避免数据丢失,事务数据库普遍采用write ahead log策略,当事务提交时,先写重做日志,再修改页。是事务(ACID)durability持久性的要求。当数据库宕机时,使用redo log恢复数据。
重做日志分为:redo log buffer 和 redo log file。
在下列3种情况下重做日志缓冲会被刷新到重做日志文件中:
- Master thread每一秒将重做日志缓冲刷新到重做日志文件(即使事务还没提交)
- 事务提交时
- 重做日志缓冲剩余空间小于1/2时
Redo 是物理日志,记录的是页的物理修改操作。而每个页有LSN
Log block 512字节。
undo log
有2个作用:保证事务的原子性(帮助事务回滚)和 一致性非锁定读(MVCC)。
Undo是逻辑日志。
Undo log 存放在一个特殊的段中,即rollback segment,在共享表空间ibdata1中。
Innodb存储引擎回滚时,做的是与先前相反的操作。
当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo log读取之前的行版本信息,实现非锁定读。
Undo log 会产生 redo log,因为undo log需要持久性保护。
Undo log 分为 insert undo log 和 update undo log,insert undo log在事务提交后,直接删除,不需要purge,而update undo log 在事务提交时,放入 undo log 链表,等待purge进行删除。可以认为:insert undo log主要用于当前事务回滚,而update undo log用于回滚和实现MVCC,事务每commit一下,就会产生一个快照。 其他事务根据这些undo log获得快照,不过在事务隔离级别为read commited和repeatable read时,取的快照不同,read commited取的是最新的快照,而repeata read取的是事务开始点的快照。
有一点,我一直想不明白,事务1开启,事务2开启,事务2新插入一条记录并提交,在rr级别下,事务1看不见新插入的数据,这到底是怎样实现的。最初以为是 insert undo log,仔细一想发现逻辑不对。我猜测应该与行的隐藏列 db_trx_id 有关,新插入的数据 db_trx_id 的值大于当前事务 id,于是不显示出来。每一个事务都有事务id,可以通过 innodb_trx 查询。
binlog
二进制日志是数据库级别的逻辑日志,在存储引擎之上。二进制日志仅在事务提交时记录,对于每一个事务,只有一条日志。
Show master status; Show variables like 'binlog_format';
使用mysqlbinlog查看二进制日志。