概述
事务的原子性和一致性由undo日志实现,持久性由redo日志实现。
redo日志用于恢复事务提交的对页的修改操作,保证事务的持久性。
undo日志用于回滚行记录到某个特定的版本,保证事务的原子性,一致性
redo log
在InnoDB存储引擎中,事务日志通过重做日志文件(redo log)和日志缓冲(InnoDB log buffer)实现。当一个事务开始时,会记录事务的一个LSN(Log Sequence Number);当事务执行时,会往InnoDB的日志缓冲中插入事务日志;当事务提交时,必须先将日志缓冲写入磁盘,换言之,就是先写日志在写数据,这种方式称作预写日志WAL(write ahead logging)。
undo log
重做日志记录了事务的行为,可以方便的通过其进行“重做”。但事务有时还需要撤销,这是就需要undo。undo与redo正好相反,undo是先写数据后记录undo log;事务对数据库进行修改时,会产生redo和undo,当有错误或rollback时,可以根据undo log将数据恢复到修改前的样子;undo存放在数据库内部的特殊段中(segment),undo段位于共享表空间内。
undo并非对数据的物理恢复,而是逻辑恢复,例如插入了10万条数据,使表空间增加,undo后表空间并不会收缩;对于每条insert,undo是做相应的delete,对于update则是做了相反的update。
binlog
binlog是MySQL server的二进制文件,用于记录数据和表结构更改操作。
binlog和redolog
区别
redolog是innodb用于保证crash-safe的一种机制,采用循环写的方式。记录的是数据的状态。
binlog是数据库层面记录数据变更的操作,采用追加写的策略。
两阶段提交
1、为什么要写两次redo log,写一次不行吗?
只写一次redo log与binlog,无法保证主节点崩溃恢复与从节点本地回放数据的一致性。
先写binlog,再写redo log:当前事务提交后,写入binlog成功,之后主节点崩溃。在主节点重启后,由于没有写入redo log,因此不会恢复该条数据。而从节点依据binlog在本地回放后,会相对于主节点多出来一条数据,从而产生主从不一致。
先写redo log,再写binlog:当前事务提交后,写入redo log成功,之后主节点崩溃。在主节点重启后,主节点利用redo log进行恢复,就会相对于从节点多出来一条数据,造成主从数据不一致。
2、奔溃恢复的过程
在写入redo log时,会顺便记录XID,即当前事务id。在写入binlog时,也会写入XID。因此存在以下三种情况:
- 若是在写入redo之前奔溃,此时无须进行任何操作,因为事务并没有提交。
- 若是在写入redo之后,binlog之前,此时redo标记为prepare状态,根据事务ID在binlog中查找,若能找到,则恢复,若找不到,则不做操作。
- 若是redolog为commit状态,则直接恢复。
redo与undo
假设有A、B两个数据,值分别为1、2,开启事务分别对其进行修改A → 3,B → 4,在提交,过程如下:
-
事务开始
-
记录A=3到redo log
-
修改A=3
-
记录A=1到undo log
-
记录B=4到redo log
-
修改B=4
-
记录B=2到undo log
-
将redo log写入磁盘
-
事务提交