我们select的时候,会把数据对应的数据页加载到缓冲池Buffer Pool,那修改的时候,其实就是修改缓冲池Buffer Pool里的缓存页数据,而不是直接修改磁盘的数据,这样性能就会有比较大的提升。但是这里会有几个问题:

  1. 事务怎么回滚?
  2. 存在缓存里机器宕机了怎么办?

    undo日志文件

    在修改缓存页数据之前,会先把数据写入undo日志文件,用来解决事务回滚。
    如果是INSERT操作,那undo日志文件就会记录主键,回滚的时候通过主键删除。
    如果是UPDATE操作,那undo日志文件就会记录修改之前的数据,回滚的时候就会用之前的数据进行恢复。
    如果是DELETE操作,那undo日志文件就会记录删除之前的数据,回滚的时候就会用之前的数据进行恢复。
    image.png

    redo日志文件

    在Buffer Pool修改数据后,接下来就是把变化的值写入到redo日志文件。
    如果此时已经写入redo日志文件,事务已经提交了,但是数据还没写入磁盘,MySql服务器宕机了,Buffer Pool里修改的数据并不会修改到磁盘里。
    当MySql重启的时候,他会读取redo日志文件,把变化的值重新写入Buffer Pool,对于客户端来说,他读取的时候,就是读取Buffer Pool的值,所以客户端读取到的数据就是新数据。
    对于写入redo和undo不一样的是,他有一个redo缓存,首先把值写入redo缓存然后再写入redo日志文件。所以他这里会有几种策略:

  3. 数据写入缓存,事务提交。
  4. 数据写入磁盘文件,事务提交。
  5. 写入缓存后事务提交,一秒后写入磁盘文件。
    从数据的可靠性来讲,我们一般选择第二种,等写入磁盘才提交事务。
    image.png
    为什么要写redo而不是直接写数据库文件呢?
    因为写入数据库文件是随机写,写入redo是顺序写,这边就有很大的性能差异。

    binlog日志文件

    实际上在redo写入后,并不会直接提交事务,而是会写入binlog归档日志,而后才会提交事务。
    与redo类似,他也提供了两种策略:

  6. 写入oscache后提交事务。
  7. 写入磁盘后提交事务。
    从数据的可靠性来讲,我们一般选择第二种,等写入磁盘才提交事务。
    image.png
    写入binlog后,他会对redo文件进行commit操作。
    比如我们修改了10条数据,然后写入binlog是8条,那我们实际提交成功的事务是多少呢?要怎么判断呢?
    此时就需要commit来判断了,当写入binlog写入后并进行commit后,才证明这条数据是成功的事务。如果没有进行commit操作,那么有可能是写入redo文件但是没有写入binlog的时候宕机了,或者已经写入binlog但是没有commit的时候宕机了,那这样的事务其实就是没有成功的。

    flush链表

    在上面的流程中,我们看到写入undo日志文件、redo日志文件、binlog归档日志,就是没有看到怎么写入磁盘的。
    在MySql中,他会有一个线程,定期的把缓存页的内容刷入到磁盘。
    那这里又有一个问题,我们知道Buffer Pool有很多缓存页,那这个线程怎么知道应该刷入哪个缓存页到磁盘呢?
    跟之前的free链表、LRU链表一样,MySql也提供了一个链表,flush链表,当缓存页的内容有修改的时候,描述数据就会加入到flush链表。
    所以这个线程每次从flush链表找到对应的缓存页,把数据刷到磁盘,然后再把他从flush链表移走。
    image.png


大军
847 声望183 粉丝

学而不思则罔,思而不学则殆