上一篇简单的介绍了下MVCC(多版本并发控制)的原理,MVCC会对事物内操作的数据做多版本控制,从而实现并发环境下事物对数据写操作的阻塞不影响读操作的性能。而这个多版本控制的实现是由undo log来实现的,下面的内容将会简单的介绍下undo log的内容。
mysql在事物开始操作数据之前,会先将原始数据备份到一个undo log的地方,这样做的目的有两个。第一是为了保证事物的原子性,如果事物在执行的过程中出现了某些错误,或者是用户执行了rollback的操作,mysql可以利用undo log中的备份将数据恢复到事物开始之前的状态。第二是为了实现多版本的并发控制,事物在提交之前,undo log中保存了未提交之前的数据版本,undo log可以作为旧版数据的快照供其他并发访问的事物实现快照读。
快照读:SQL读取的数据是快照版本,也就是历史版本,普通的select查询的就是快照。innodb存储引擎的快照读,读取的数据将由cache(原始数据)+undo(事物修改过的数据)两部分组成。
当前读:SQL读取的数据是最新版本,可以通过锁的机制来保证读取的数据无法被其它的事物修改。update,delete,insert,select ... lock in share mode,select ... for update都是当前读。
除了undo log,Mysql数据库还有一个redo log的概念,mysql在事物开始之后,事物中操作的任何数据,会将最新的数据备份到一个地方(redo log),就是在事物执行的过程中,开始将数据写入redo buffer中,最后写入redo log中,具体的落盘策略可以自行配置。这样做的目的是:为了实现事物的持久性,防止在发生故障的时间点,尚有脏页未写入磁盘,在mysql重启的时候,根据redo log重做,从而使事物未入磁盘的数据达到持久化这一特定。
说明:指定的redo log是记录在{datadir}/ib_logfile1&ib_logfile2,可以通过innodb_log_group_home_dir配置指定的目录存储。一旦事物提交成功,并且数据持久化落盘之后,redo log中的数据也就失去了意义,所以redo log中的写入是日志文件循环写入的。可以配置下列参数:
指定redo log日志文件组中的数量 innodb_log_files_in_group 默认为2
指定redo log每一个日志文件最大存储量innodb_log_file_size 默认48M 指定redo log在cache/buffer中的buffer池大小innodb_log_buffer_size 默认16Mredo log的落盘策略,即将数据从redo buffer持久化到磁盘的redo log文件中,可配置Innodb_flush_log_at_trx_commit参数,这个参数的取值有以下几种情况。
取值0,每秒提交redo buffer -> redo log os cache -> flush cache to disk,这种情况可能丢失一秒内的事物数据。
取值1,该参数的默认值,每次事物提交执行redo buffer -> redo log os cache -> flush cache to disk,这种情况可能丢失一个事物的数据,最安全,但同时性能最差。 取值2,每次事物提交执行redo buffer -> redo log os cache,在每一秒执行 -> flush cache to disk操作。关于undo log和redo log,有下面的图可以参考。
说明:undo log和redo log可以理解为都是对数据的备份,其中undo log是对旧数据(原始数据)的备份,redo log是对新数据(事物所要提交的数据)的备份。对数据的备份首先是会存储在各自的buffer中,即undo buffer和redo buffer,至于如何持久化到磁盘,即写入到undo log和redo log文件中,要根据设置的具体落盘策略而定。