我们select的时候,会把数据对应的数据页加载到缓冲池Buffer Pool,那修改的时候,其实就是修改缓冲池Buffer Pool里的缓存页数据,而不是直接修改磁盘的数据,这样性能就会有比较大的提升。但是这里会有几个问题:
- 事务怎么回滚?
存在缓存里机器宕机了怎么办?
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日志文件。所以他这里会有几种策略:- 数据写入缓存,事务提交。
- 数据写入磁盘文件,事务提交。
写入缓存后事务提交,一秒后写入磁盘文件。
从数据的可靠性来讲,我们一般选择第二种,等写入磁盘才提交事务。
为什么要写redo而不是直接写数据库文件呢?
因为写入数据库文件是随机写,写入redo是顺序写,这边就有很大的性能差异。binlog日志文件
实际上在redo写入后,并不会直接提交事务,而是会写入binlog归档日志,而后才会提交事务。
与redo类似,他也提供了两种策略:- 写入oscache后提交事务。
写入磁盘后提交事务。
从数据的可靠性来讲,我们一般选择第二种,等写入磁盘才提交事务。
写入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链表移走。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。