查看原文
其他

面试必须要知道的MySQL知识--三大日志和事务

三友 三友的java日记 2022-10-31

欢迎点击关注公众号,利用碎片化时间学习,每天进步一点点。

来源:https://blog.csdn.net/a18602320276/article

/details/122917218



本文接着 面试必须要知道的MySQL知识(上)继续剖析MySQL的三大日志和事务的原理。

6 redo log

6.1 概念

第三章我们从 InnoDB 架构设计提到了 redo log,这一章我们具体来聊一聊 redo log。


redo log 是 InnoDB 独有的,本质上只是记录了一下事务对数据库做了哪些修改。与在事务提交时将所有修改过的内存中的页面刷新到磁盘中相比,只将该事务执行过程中产生的 redo 日志刷新到磁盘的好处如下 :

  • redo 日志占用的空间非常小,内存利用率高

  • redo 日志是顺序写入磁盘的,性能较高


6.2 图解

redo log 里本质上记录的就是在对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值,具体修改的值是什么,他里面需要记录的就是表空间号+数据页号+偏移量+具体的值。redo 日志有很多种,以下是常见的一种。



6.3 redo log block

为了更好的进行系统崩溃恢复,MySQL 把 redo log 都放在了大小为 512 字节的 redo log block 中 。

redo log block 分为以下 3 个部分:

  • header
    存放了一些管理信息。

  • body
    redo log 真正存放的地方。

  • traller
    存放了一些管理信息。


其中 header 存放的内容如下:



整个 redo log 写入的流程,总结如下:



6.4 redo log buffer

首先让我们回顾一下下面这张图


为了增加数据更新的效率,MySQL 引入了 BufferPool 的概念;同理,为了增加 redo log 的效率,MySQL 同样引入了 redo log buffer 的概念,它其实就是 redo log 的缓冲区,它包含了若干个连续的 redo log block。最后,我们要知道 redo log 都是先进入 redo log buffer 中的一个 block,然后事务提交的时候才会刷入磁盘文件里去。那么这里会有两种情况


  • 事务没提交,MySQL 挂了

    这种情况,丢了就丢了,没有影响,不需要重做。


  • 事务提交了,MySQL 挂了,但是已经被修改的缓存页还没有被刷入磁盘

    这种情况因为有 redo log 存在,你重启 MySQL 之后,可以把没来得及刷入磁盘的事务,他们所对应的 redo log 都加载出来,再在 BufferPool 的缓存页里重做一遍,就可以保证事务提交之后,修改的数据绝对不会丢。


7 undo log

7.1 概念

通过上文我们知道了 redo log 保证了事务提交后的数据,不会丢。但是如果事务执行到一半就 GG 了怎么办?为了保证事务的原子性,我们需要把东西改回原先的样子,这个过程就称之为回滚。MySQL 的回滚主要依赖于 undo log。


undo log 记录的东西也很简单,比如插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉就好了。


7.2 图解


8 bin log

8.1 概念

前面我们对 redo log 做了介绍,它是一种重做日志,它主要关注“哪个数据页的哪个数据做了什么修改。


bin log 叫做归档日志,它主要关注“对哪个表的哪个数据做了什么操作,操作之后是什么”。


我们可以这样理解 bin log 是偏向于逻辑性的日志,而 redo log 更偏向于物理性。


注意:bin log 不是 InnoDB 存储引擎特有的日志文件,是属于 MySQL server 自己的日志文件。


8.2 bin log 和 redo log的区别

  • bin log 是MySQL本身就拥有的,不管哪种存储引擎;redo log 是InnoDB独有的。

  • bin log是一种逻辑日志,redo log 是一种物理日志。

  • bin log没有幂等性,redo log具有幂等性,多次操作前后的状态是一致的。

  • bin log开启事务的时候,会将每一次提交的事务一次性写入内存缓冲区,如果未开启事务,则每次进行增删改时,就会将对应事务信息写入内存缓冲区;而redo log是在数据准备修改之前,将数据写入缓冲区redo log中的,然后在缓冲区中修改数据,而且在提交事务的时候,现将redo log 写入缓冲区,写入完成后,再提交事务。

  • bin log只会在事务提交时,一次性写入bin log;redo log最后一个提交的事务记录会覆盖之前所有未提交的事务记录,并且一个事务的redo log中间会插入其他事务的redo log。

  • bin log是追加写入,不会覆盖;redo log是循环写入,会覆盖。

  • bin log一般用于主从复制和数据恢复;redo log 一般用于MySQL,重启后恢复事务已提交但未写入数据表的数据。


9 事务

在开始新篇章之前,让我们回顾一下,下面的流程


1、MySQL 事务执行流程


2、MySQL 事务恢复流程

9.1 脏写与脏读

9.1.1 概念

如果一个事务修改了另一个未提交事务修改过的数据,那就意味着发生了脏写 。

如果一个事务读到了另一个未提交事务修改过的数据,那就意味着发生了脏读 。

9.1.2 分析

  • 脏读

    原始数据为 null

    事务 A 更新数据为 A

    事务 B 查询数据为 A

    事务 A 这个时候回滚了,那么它用它的 undo log 去回滚,现在数据为 null

    事务 B 再次查询数据为 null


  • 脏写

    原始数据为 null

    事务 A 更新数据为 A

    事务 B 更新数据为 B

    事务 A 这个时候回滚了,那么它用它的 undo log 去回滚,现在数据为 null

    事务 B 再次查询数据为 null,事务B修改的数据丢失了


9.2 不可重复读

9.2.1 概念

如果一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值,那就意味着发生了不可重复读。

9.2.2 分析

  • 原始数据为 A

  • 事务 A 查询数据为 A

  • 事务 B 更新数据为 B,并提交

  • 事务 A 查询数据为 B

  • 事务 C 更新事务为 C,并提交

  • 事务 A 查询数据为 C


9.3 幻读

9.3.1 概念

如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读。

9.3.2 分析

  • 事务 B 插入数据 1 条,总数 11 条

  • 事务 A 查询数据为 11 条

  • 事务 B 这个时候回滚了,总数变为 10 条

  • 事务 A 查询数据为 10 条


9.4 隔离级别

9.4.1 SQL 标准中的四种隔离级别

9.4.2 MySQL 标准中的四种隔离级别


READ UNCOMMITTED 我们上文提到的几种问题,他都没有解决,所以正常人都不会使用它;


SERIALIZABLE 效率太低,也没人会用他;


READ COMMITTED 在某些需要不可重复读的情况下,会用到,但是这种情况,如果你是用的 Spring 框架,那么可以在代码里单独指定,生产中的 MySQL 数据库级别一般也不是它;


REPEATABLE READ 这个是 MySQL 默认的隔离级别,这里我们需要注意的是,在 RR 隔离级别下,MySQL 解决了幻读问题,具体是怎么解决的呢?下文将会从 undo log 版本链讲起。


9.5 undo log 版本链

9.5.1 概念

简单来说呢,我们每条数据其实都有两个隐藏字段,一个是 trx_id,一个是 roll_pointer,这个 trx_id 就是最近一次更新这条数据的事务 id,roll_pointer 就是指向你了你更新这个事务之前生成的 undo log,接着假设有一个事务 B 跑来修改了一下这条数据,把值改成了值 B,事务 B 的 id 是 15,那么此时更新之前会生成一个 undo log 记录之前的值,然后会让 roll_pointer 指向这个实际的 undo log 回滚日志。

9.5.2 图解


↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓



↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓



9.6 MVCC机制

MVCC机制公众号曾发过文章详细剖析过,里就直接引用之前的的文章


正确理解MySQL的MVCC及实现原理


本文完。后面还会有一篇文章跟大家剖析MySQL的锁机制。欢迎大家持续关注本公众号,及时获得下文。


如果觉得这篇文章对你有所帮助,还请帮忙点赞、在看、转发一下,非常感谢!


往期热门文章推荐

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存