咱们 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 链表移走。