通过本讲,你将学到redo log、bin log、undo log日志系统的产生、释放过程,作用,以及与事务(ACID)的关系。
事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commit ),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚( rollback )到最初状态。
事务有4种特性:原子性、一致性、隔离性和持久性。
指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚
指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态。这种状态是语义上的而不是语法上的,跟具体的业务有关。
指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
事务的持久性是通过事务日志来保证的,包括重做日志(redo log)和回滚日志(undo log)。
当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志(redo log)中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。
而当事务需要回滚的时候,就用到了回滚日志(undo log),从而使事务具备原子性和一致性。
简单整理下他们的关系:
redo log 和 undo log 是InnoDB存储引擎层的日志,bin log 是MySQL Server层记录的日志, 两者都是记录了某些操作的日志(不是所有),自然有会些重复,但两者记录的格式不同。
用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。
作用:
确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
内容:
redo log是物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。
产生:
redo log是循环写,日志空间大小固定。
事务开始之后就产生redo log,redo log 的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中便开始写入redo log文件中。原因就是,重做日志有一个缓存区Innodb_log_buffer,Innodb_log_buffer的默认大小为8M,Innodb存储引擎先将重做日志写入innodb_log_buffer中。
释放:
当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志(redo log)占用的空间就可以重用(被覆盖)。
将innodb日志缓冲区的日志刷新到磁盘的三种方式:
即使某个事务还没有提交,Innodb存储引擎仍然每秒会将重做日志缓存刷新到重做日志文件。这一点是必须要知道的,因为这可以很好地解释再大的事务的提交(commit)的时间也是很短暂的。
undo log是在事务开始之前保存的被修改数据的一个版本,产生undo日志的时候,同样会伴随类似于保护事务持久化机制的redolog的产生。
作用:
保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。
内容:
逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。
undo表空间可以配置成独立的文件,但是提前需要在配置文件中配置,完成数据库初始化后生效且不可改变undo log文件的个数。如果初始化数据库之前没有进行相关配置,那么就无法配置成独立的表空间了。
产生:
事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性。
释放:
当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。
bin log 是MySQL Server层记录的日志,所有引擎都可以使用,这样在数据库用别的存储引擎时可以达到一致性的要求。
作用:
用于数据复制和数据还原。在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
内容:
逻辑格式的日志。包括了执行的sql语句(增删改)以及反向的信息,也就意味着delete对应着delete本身和其反向的insert;update对应着update执行前后的版本的信息;insert对应着delete和insert本身的信息。
因此可以基于binlog做到类似于oracle的闪回功能,其实都是依赖于binlog中的日志记录。
产生:
binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到 bin log 中。这里与 redo log 很明显的差异就是 redo log 并不一定是在事务提交的时候刷新到磁盘,redo log是在事务开始之后就开始逐步写入磁盘。
因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的,但是在开启了bin_log的情况下,对于较大事务的提交,可能会变得比较慢一些。这是因为 bin log 是在事务提交的时候一次性写入的造成的。
释放:
bin log 的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。
三种日志的区别:
如何保证主从复制的数据一致性?(两阶段提交)
理论上MySQL是先写redo log,再写binlog,两个日志都提交成功(刷入磁盘),事务才算真正的完成。写入redo的过程分为了prepare和commit称为二阶段提交。
一条更新语句执行的顺序:
连接器、分析器、优化器之后,调用操作引擎,将新行写入内存,写入redo log(状态为prepare)-> 写binlog -> redo log状态修改为commit。
redo log:重做日志,属于物理日志,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。
更新语句执行时,InnoDB引擎会把更新记录写到redo log日志中,然后更新内存,此时算是语句执行完了,然后在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中,关键点是先写日志,再写磁盘。
undo log:回滚日志,提供回滚操作,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读;