系列文章:
一 背景知识
有了前面的一些知识,和redo、undo、binlog,以及事务隔离级别的基本理解,下面我们整理事务提交的详细过程。
首先再明确一下几个log的作用:
1、redo
重做日志,用于实现事务的持久性,即ACID中的D。结合本系列的第一篇文章,【Mysql-InnoDB 系列】InnoDB 架构包括内存架构和磁盘架构两部分。redo日志在存储体现上也由两部分组成:
1-1 内存中的重做日志缓冲(redo log buffer),因为内存中是缓存,所以是易失的,server挂掉或机器断点等原因导致宕机后丢失;
1-2 重做日志文件(redo log file),在磁盘上默认是两个文件存储。循环写入。
2、undo
redo日志记录事务的行为,用于对页进行“重做”操作。但我们都知道事务还有rollback动作,回滚时需要undo,利用其信息把数据回滚到修改之前。undo是逻辑日志,只是将数据库逻辑地恢复到原来的样子,但数据结构和页本身在回滚之后可能大不相同。
另外,undo还有一个作用,就是在MVCC中提供快照。这需要借助一个名为history list的结构,把undo log组织成一个链表:
3、binlog
二进制日志,用于进行POINT-IN-TIME(PIT)恢复及主从复制(Replication)。与redo log区别:
(1)redo log是InnoDB存储引擎层产生的,而 binlog是Mysql数据库上层产生的;binlog不仅仅针对InnoDB引擎,MySQL数据库中的任何存储引擎对数据库的更改都会产生binlog。
(2)内容形式。binlog是一种逻辑日志,记录的是SQL语句。而InnoDB存储引擎层面的redo log是物理格式日志,记录的是对每个页的修改
(3)写入时间点:binlog只在事务提交完成后进行一次写入,而redo log在事务进行中不断被写入,表现:日志并不是随事务提交的顺序进行写入的。如下图所示:
二 事务提交过程
1、开启二进制日志后的事务提交过程,两阶段提交::
(1)事务提交时InnoDB存储引擎进行prepare操作
(2)MySQL数据库上层写入binlog
(3)InnoDB存储引擎层将日志写入redo log文件
a)修改内存中事务对应的信息,并将日志写入redo log buffer
b)调用fsync将确保日志都从redo log buffer写入磁盘
一旦MySQL数据库上层写入binlog完成,就保证了事务的提交,即使之后数据库挂掉导致redo log未完成。此外还有一点必须注意,每个步骤都必须进行一次fsync才能保证上下层数据的一致。步骤(2)的fsync由sync_binlog控制,(3)的fsync由参数innodb_flush_log_at_trx_commit控制。
2、InnoDB存储引擎事务提交顺序与上层的二进制日志
3、锁prepare_commit_mutex保证事务提交与binlog写入顺序:
三 总结
MySQL InnoDB的事务模型、锁机制等设计,都是InnoDB架构设计的一部分。要全面了解它的设计实践,就必须从头看起。只有这样,才能够弄清楚它的设计思想,理解其实现上的精妙之处。
例如在上一篇文章中提到的问题,关于事务、redolog 写入的两个问题分析 ,看似简单,在网上也能搜到不少文章,但不深入了解,还是会有很多疑惑,甚至是理解错误。“重做日志”就是很典型的一个。 在整个系列中,redo log指的是一种数据,但也可能是在说它的所在位置、存储形式【即 内存中的redo log buffer, 以及磁盘上的:ib_logfile文件】。如果不结合上下文和具体流程,那么就可能无法正确区分说的是哪一种情况。
不积跬步,无以至千里。立足脚下,基础扎实,才能走得更远。