MySQL8.0 MySQL事务日志、REDO日志、UNDO日志

文章目录

  • 学习资料
  • MySQL事务日志
    • REDO日志
      • REDO日志的好处、特点
        • 好处
        • 特点
      • REDO的组成
      • REDO的整体流程
      • REDO LOG的刷盘策略
        • 流程图
    • UNDO日志
      • 如何理解UNDO日志
      • UNDO日志的作用
        • 作用1:回滚数据
        • 作用2:MVCC
    • 小结


学习资料

【MySQL数据库教程天花板,mysql安装到mysql高级,强!硬!-哔哩哔哩】
【阿里巴巴Java开发手册】https://www.w3cschool.cn/alibaba_java

MySQL事务日志

事务日志4种特性:原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢?
事务的隔离性由锁机制实现。
而事务的原子性、一致性和持久性由事务的redo日志和undo日志来保证。
REDO LOG称为重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。
UNDO LOG称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
有的DBA或许会认为UNDO是REDO的逆过程,其实不然。REDO和UNDO都可以视为一种恢复操作,但是:

redo log:是存储引擎层(innodb)生成的日志,记录的是物理级别上的页修改操作,比如页号xxx、偏移量yyy写入了‘zzz’数据。主要为了保证数据的可靠性;

undo log:是存储引擎(innodb)生成的日志,记录的是逻辑操作日志,比如对某一行数据进行了INSERT语句操作,那么undo log就记录一条与之相反的DELETE操作。主要用于事务的回滚(undo log记录的是每个修改操作的逆操作)和一致性非锁定读(undo log回滚行记录到某种特定的版本—MVCC,即多版本并发控制)。

REDO日志

InnoDB存储引擎是以页为单位来管理存储空间的。在真正访问页面之前,需要把磁盘上的页缓存到内存中的Buffer Pool之后才可以访问。所有的变更都必须先更新缓冲池中的数据,然后缓冲池中脏页会以一定的频率被刷入磁盘(chekPoint机制),通过缓冲池来优化CPU和磁盘之间的鸿沟,这样就可以保证整体的性能不会下降太快。

REDO日志的好处、特点

好处

redo日志降低了刷盘频率
redo日志占用的空间非常小
存储表空间ID、页号、偏移量以及需要更新的值,所需的存储空间是很小的,刷盘快。

特点

redo日志是顺序写入磁盘的
在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的,也就是使用顺序IO,效率比随机IO快。
事务执行过程中,redo log不断记录
redo log跟bin log的区别,redo log是存储引擎层产生的,而bin log是数据库层产生的。假设一个事务,对表做10万行的记录插入,在这个过程中,一直不断的往redo log顺序记录,而bin log不会记录,直到这个事务提交,才会写入到bin log文件中。

REDO的组成

Redo log可以简单分为以下两个部分:
重做日志的缓冲(redo log buffer),保存在内存中,是易失的。
在服务器启动时就像操作系统申请了一大片称之为redo log buffer的连续内存空间,翻译成中文就是redo日志缓冲区。这片内存空间被划分成若干个连续的redo log block。一个redo log block占用512字节大小。
MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第1张图片
参数设置:innodb_log_buffer_size
redo log buffer大小,默认16M,最大值是4096M,最小值为1M。

重做日志文件(redo log file),保存在硬盘中,是持久的。

REDO的整体流程

MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第2张图片

体会:Write-Ahead Log(预先日志持久化):在持久化一个数据页之前,先将内存中相应的日志页持久化。

REDO LOG的刷盘策略

redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后一定的频率刷入到真正的redo log file中。这里的一定频率怎么看待呢?这就是我们要说的刷盘策略。MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第3张图片
注意,redo log buffer刷盘到redo log file的过程并不是真正刷到磁盘中去,只是刷到了文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。

针对这种情况,InnoDB给出innodb_flush_log_at_trx_commit参数,该参数控制commit提交事务时,如何将redo log buffer中的日志刷新到redo log file中。它支持三种策略:
设置为0:表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日志的同步)。
设置为1:表示每次事务提交时都将进行同步,刷盘操作(默认值)。
设置为2:表示每次事务提交时都只把redo log buffer内容写入page cache,不进行同步。由os自己决定什么时候同步到磁盘文件。
MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第4张图片
另外,InnoDB存储引擎有一个后台线程,每个1秒,就会把redo log buffer中的内容写到文件系统缓存(page cache),然后调用刷盘操作。
MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第5张图片
也就是说一个没有提交事务的redo log记录,也可能会刷盘。因为事务执行过程redo log记录是会写入redo log buffer中,这些redo log记录会被后台线程刷盘。
MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第6张图片
除了后台线程每秒1次的轮询操作,还有一种情况,当redo log buffer占用的空间即将达到innodb_log_buffer_size(这个参数默认是16M)的一半的时候,后台线程会主动刷盘。

流程图

可通过show variables like 'innodb_flush_log_at_trx_commit';查看

MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第7张图片
小结:innodb_flush_log_at_trx_commit=1
1时,只要事务提交成功,redo log记录就一定在硬盘里,不会有任何数据丢失。
如果事务执行期间MySQL挂了或宕机,这部分日志丢了,但事务并没有提交,所以日志丢了也不会有任何损失,可以保证ACID的D,数据绝对不会丢失,但是效率最差的。
建议使用默认值,虽然操作系统宕机的概率理论小于数据库宕机的概率,但是一般既然使用了事务,那么数据的安全相对来说更重要一些。

MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第8张图片
小结:innodb_flush_log_at_trx_commit=2
2时,只要事务提交成功,redo log buffer中的内容只写入文件缓存(page cache)。
如果仅仅只是MySQL挂了不会有任何数据丢失,但是操作系统宕机可能会有1秒数据的丢失,这种情况下无法满足ACID中的D。但数值2肯定是效率最高的。

MySQL8.0 MySQL事务日志、REDO日志、UNDO日志_第9张图片
小结:innodb_flush_log_at_trx_commit=0
0时,master thread中每1秒进行一次重做日志的fsync操作,因此实例crash最多丢失1秒钟内的事务。(master thread是负责将缓冲池中的数据异步刷新到磁盘,保持数据的一致性)。
数值0的话,是一种折中的做法,它的IO效率理论是高于1的,低于2的,这种策略也有丢失数据的风险,也无法保证D。

UNDO日志

redo log是事务持久性的保证,undo log是事务原子性的保证。在事务中更新数据前置操作其实是要先写入一个undo log

如何理解UNDO日志

事务需要保证原子性,也就是事务中操作要么全部完成,要么什么也不做。但有时候事务执行到一半会出现一些情况,比如:
情况一:事务执行过程中可能遇到各种错误,比如服务器本身的错误操作系统错误,甚至是突然断电导致的错误。
情况二:程序员可以在事务执行过程中手动输入ROLLBACK语句结束当前事务的执行。
以上情况出现,我们需要把数据改回原先的样子,这个过程称之为回滚,这样就可以造成一个假象:这个事务看起来什么都没做,所以符合原子性要求。

每当我们要对一条记录做改动时(这里的改动可以指INSERT、DELETE、UPDATE),都需要“留一手” 一 一 把回滚时所需的东西记下来。比如:
插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉就好了。(对于每个INSERT,InnoDB存储引擎会完成一个DELETE)。
删掉了一条记录,至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了。(对于每个DELETE,InnoDB存储引擎会执行一个INSERT)。
修改了一条记录,至少要把修改这条记录前的旧值都记录下来,这样之后回滚再把这条记录更新为旧值就好了。(对于每个UPDATE,InnoDB存储引擎会执行一个相反的UPDATE,将修改前的行放回去)。

MySQL把这些为了回滚而记录的这些内容称之为撤销日志或者回滚日志(即undo log)。注意,由于查询操作(SELECT)并不会修改任何用户记录,所以在查询操作执行时,并不需要记录相应的undo日志。

此外,undo log会产生redo log,也就是undo log的产生会伴随着redo log的产生,这是因为undo log也需要持久性的保护。

UNDO日志的作用

作用1:回滚数据

用户对undo日志可能有误解:undo用于将数据库物理地恢复到执行语句或事物之前的样子。但事实并非如此。undo是逻辑日志,因此只是将数据库逻辑恢复到原来的样子。所有修改都被逻辑地取消了,但是数据结构和页本身在回滚之后可能大不相同。

这是因为在多用户并发系统中,可能会有数十、数百甚至数千个并发事务。数据库的主要任务就是协调对数据记录的并发访问。比如,一个事务在修改当前一个页中某几条记录,同时还有别的事务在对同一个页中另几条记录进行修改。因此,不能将一个页回滚到事务开始的样子,因为这样会影响其他事务正在进行的工作。

作用2:MVCC

undo的另一个作用是MVCC,即InnoDB存储引擎中MVCC的实现是通过undo来完成。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取。

小结

undo log是逻辑日志,对事务回滚时,只是将数据库逻辑地恢复到原来的样子。
redo log是物理日志,记录的是数据页的物理变化,undo log不是redo log的逆过程。

你可能感兴趣的:(MySQL8.0从入门到高级,mysql,数据库,sql)