mysql-事务日志
Posted Zheng"Rui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql-事务日志相关的知识,希望对你有一定的参考价值。
事务日志
mysql中的事务日志分为三类,分别是:redo log,undo long,bin log,这里只介绍redo log和undo log
一、redo log
1.1 基本介绍
redo log是重做日志,其中存放的是事务对数据页的物理修改,比如‘在某一行插入了一个数据’,innodb可以根据重做日志,恢复数据。
redo log分为两个部分:
1.是在内存中的 redo log buffer,是易失的。
2.是在磁盘上的redo file,是持久的。
innodb更新数据的全流程:
1.首先将数据页从磁盘中缓存到内存中
2.更新内存中的数据
3.将更新操作信息转化成redo日志,保存在redo log buffer中
4.根据redo log的刷新规则(可以指定),这里假设是事务结束时,自动刷新。当事务结束时,就会把redo log buffer中的内容刷新到redo file中进行持久化。
5.根据数据页的刷新机制,将脏数据页(也就是在内存中修改了,但是还没有写入磁盘的数据页)进行写入磁盘。
1.2 double write
innodb在更新数据的时候,会有两次写磁盘操作,叫做double write。造成需要两次写操作的原因,简单来说,是因为防止系统宕机,导致数据丢失。
1.2.1 partial page write
首先来介绍partial page write(部分页写入),我们知道mysql在内存中,对于数据是采用16KB为一页进行管理的,也是mysql操作数据页的基本单位。当需要将更新数据页写回磁盘时,会出现一个问题,就是操作系统对于每一次写操作的基本单位是512字节,这种不匹配导致,对于mysql一个数据页的写于磁盘操作不在是原子性的了,也就是说,当磁盘写到一半,发生断电等情况的时候,可能只写入了一半的数据,这些数据就变得不可靠,要想恢复数据,我们很容易想到使用redo log进行恢复,但是需要注意,服务器重启之后,内存中的数据已经丢失了,磁盘上的数据也被部分修改了,我们没有办法找到一个合适的”起点“,来进行redo,所以,这个时候就需要寻找一个备份,防止这种情况的产生。
1.2.2 double write 机制
为了给redo log提供一个起点,我们需要在每次修改数据,写入磁盘的时候,先进行备份数据的写入,这样,就算下次写数据的时候宕机了,还是可以把备份数据拿出来,恢复原来的页数据,然后通过redo log,恢复最新的数据。
引入double write后的刷新数据流程:
1.首先在刷新机制触发的时候,将脏数据页先也入内存中的double write buffer中,然后通过double write buffer将脏数据页先也如到磁盘的共享表空间中,此时是顺序io,速度比较块,写完之后,将脏数据页在离散的写入到磁盘data file中。
如果此时在发送断电宕机,重启之后,可以从共享表空间中,取出之前的数据,也就是起点,然后根据redo log进行重做,即可恢复数据。
那如果写入共享表空间失败了呢?其实是同样的原理,因为写入共享表空间是追加写入的,我们同样可以那之前的数据作为起点,然后根据redo log进行数据恢复。
二、undo log
2.1 基本介绍
undo log也叫回滚日志,是用来纪录数据的版本链的,以此来支持事务的回滚。
首先介绍,在innodb中,会对每一个数据表添加三个默认字段,这三个默认字段,用户没有办法通过任何方式进行显示,但是查看源码是可以看到的。
1.db_row_id:这是innodb为每一个数据行添加的默认自增主键,当数据表中没有主键的时候,会使用该默认主键作为索引。
2.db_roll_ptr:回滚指针,指向该数据行的上一个版本
3.db_trx_id:最近一次修改该数据行的事务id。
每一次,我们对数据行进行修改的时候,其实都会先复制一份最新的数据,然后将其回滚指针指向之前的数据行,然后将最近一次修改的事务id换成当前事务的事务id,然后才会修改数据。当需要回滚数据的时候,只需要按照回滚指针,匹配事务id即可进行回滚。
2.2 MVCC
上一篇文章我们说过,mysql采用读写锁来进行并发控制,读锁直接是共享的,但是写锁是会阻塞读锁和写锁的,这当然已经提高了性能,但是对于大数据量的并发来说,还是不够,同一时间只能有一个事务对数据进行写操作,这个没问题,但是对于mysql的使用,大多是是查询工作,能不能想个办法,然后进行写数据的时候,其他事务也可以进行读呢?
MVCC就是折中的解决办法。通过undo log我们知道,innodb中其实是存放了不同版本的数据的,那么我们是否可以然后写事务操作最新版本的数据,让读事务去读旧版本的数据,这样可以实现读写的真正并发。
MVCC的实现其实是靠read view读视图来实现的,当一个事务第一次进行select进行快照读的时候,会根据一定的读视图生成逻辑,生成读视图,再次之后,根据隔离级别的不同,会有不同的表现,如果是RR级别下,之后的每一次select快照读,其实都是在读取之前的读视图,不管其他事务有没有修改,有没有删除,有没有提交,都不会影响到当前事务的读取,这就避免了脏读,幻读,不可重复读的问题。但是在RC级别下,每一次select快照读都会重新生成读视图,也就是每一次都会读取最新的数据,这也就是为什么RC级别下每一次select都能够读到别的事务提交的内容的原因了。
以上是关于mysql-事务日志的主要内容,如果未能解决你的问题,请参考以下文章