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

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

    undo日志文件

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

    redo日志文件

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

  3. 数据写入缓存,事务提交。
  4. 数据写入磁盘文件,事务提交。
  5. 写入缓存后事务提交,一秒后写入磁盘文件。
    从数据的可靠性来讲,咱们个别抉择第二种,等写入磁盘才提交事务。

    为什么要写redo而不是间接写数据库文件呢?
    因为写入数据库文件是随机写,写入redo是程序写,这边就有很大的性能差别。

    binlog日志文件

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

  6. 写入oscache后提交事务。
  7. 写入磁盘后提交事务。
    从数据的可靠性来讲,咱们个别抉择第二种,等写入磁盘才提交事务。

    写入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链表移走。