分享

MySQL笔记 - InnoDB存储引擎

 新用户73336046 2023-11-22 发布于浙江

收藏小程序 玲轩阁 大量资源免费分享

假设我们有下面这样一条SQL语句:

update users set name = 'xxxx' where id = 10;

这样一条SQL语句是如何执行的呢?

首先肯定的是我们的系统通过一个数据库连接发送到MySQL上,然后肯定会经过SQL接口、解析器、优化器、执行器几个环节,解析SQL语句,生成执行计划,接着去由执行器负责这个计划的执行;调用InnoDB存储引擎的接口去执行。

InnoDB的重要内存结构:缓冲池

InnoDB存储引擎中有一个非常重要的放在内存里的组件,就是缓冲池(Buffer Pool),这里面会缓存很多的数据,以便于以后在查询的时候,万一你要是内存缓冲池里有数据,就可以不用去查磁盘了。

引擎要执行更新语句的时候,比如对"id=10"这一行数据,他其实会先将"id=10"这一行数据看看是否在缓冲池里,如果不在的话,那么会直接从磁盘里加载到缓冲池里来,而且接着还会对这行记录加独占锁。

在更新"id=10"这一行数据的时候,肯定是不允许别人同时更新的,所以必须要对这行记录加独占锁。

undo日志文件:如何让你更新的数据可以回滚

接着下一步,假设"id=10"这行数据的name原来是"zhangsan",现在我们要更新为“xxx”,那么此时我们得先把要更新的原来的值"zhangsan"和"id=10"这些信息,写入到undo日志文件中去。

只要稍微对数据库有一点了解就应该知道,如果我们执行一个更新语句,要是他在一个事务里的话,那么事务提交之前我们都是可以对数据进行回滚的,也就是把你更新为"xxx"的值回滚到之前的“zhangsan”去。

所以为了考虑到未来可能要回滚数据的需要,这里会把你更新前的值写入undo日志文件。

更新buffer pool中的缓存数据

当我们把要更新的那行记录从磁盘文件加载到缓冲池,同时对他加锁之后,而且还把更新的旧值写入undo日志文件之后,我们就可以正式开始更新这行记录了,更新的时候,先是会更新缓冲池中的记录,此时这个数据就是脏数据了。

这里所谓的更新内存缓冲池里的数据,意思就是把内存里"id=10"这行数据的name字段修改为"xxx",那么为什么说此时这行数据就是脏数据了呢?

因为这个时候磁盘上"id=10"这行数据的name字段还是"zhangsan",但是内存里这行数据已经被修改了,所以就会叫他是脏数据。

更新buffer pool中的缓存数据

当我们把要更新的那行记录从磁盘文件加载到缓冲池,同时对他加锁之后,而且还把更新的旧值写入undo日志文件之后,我们就可以正式开始更新这行记录了,更新的时候,先是会更新缓冲池中的记录,此时这个数据就是脏数据了。

这里所谓的更新内存缓冲池里的数据,意思就是把内存里"id=10"这行数据的name字段修改为"xxx",那么为什么说此时这行数据就是脏数据了呢?

因为这个时候磁盘上"id=10"这行数据的name字段还是"zhangsan",但是内存里这行数据已经被修改了,所以就会叫他是脏数据。

这个redo日志其实是用来在MySQL突然宕机的时候,用来恢复你更新过的数据的。

如果还没提交事务,MySQL宕机了怎么办?

到目前为止,其实还没有提交事务,那么此时如果MySQL崩溃,必然导致内存里Buffer Pool中的修改过的数据丢失,同时写入Redo Log Buffer中的redo日志也会丢失。

此时数据丢失其实是不要紧的,因为一条更新语句,没提交事务,就代表他没执行成功,此时MySQL宕机虽然导致内存里的数据丢失了,但是你会发现磁盘上的数据依然还停留在原样子。

也就是说"id=1"的那行数据的name字段的值还是老的值"zhangsan",所以此时你的这个事务就是执行失败了,没能成功完成更新,你会收到一个数据库的异常,然后当mysql重启之后,数据并没有任何变化。所以此时mysql宕机,不会有任何问题。

提交事务的时候将redo日志写入磁盘中

接着我们想要提交一个事务,此时就会根据一定的策略把redo日志从redo log buffer里刷入到磁盘文件里去。此时这个策略是通过
innodb_flush_log_at_trx_commit来配置的,他有几个选项:

  1. 当这个参数的值为0的时候,那么你提交事务的时候,不会把redo log buffer里的数据刷入磁盘文件的,此时可能你都提交事务了,结果mysql宕机,此时内存里的数据全部丢失。

  2. 当这个参数的值为1的时候,提交事务的时候,就必须把redo log从内存刷入到磁盘文件里去,只要事务提交成功,那么redo log就必然在磁盘里了。那么只要提交事务成功之后,redo日志一定在磁盘文件里,此时就会有一条redo日志表明"我此时对哪个数据做了一个什么修改,比如name字段修改为xxx"。

  3. 然后哪怕此时buffer pool中更新过的数据还没有刷入到磁盘里去,此时内存里的数据已经更新成"xxx",然后磁盘上的数据还是没更新过的 "name=zhangsan"。

  4. 此时如果mysql突然宕机,数据也不会丢失,因为redo日志中已经记录了修改记录,当mysql重启后,可以根据redo日志恢复之前做过的修改。

  5. 如果这个参数的值为2,意思是提交事务的时候,把redo日志写入磁盘文件对应的os cache缓存里去,而不是直接写入磁盘文件,可能1秒后才会把os cache里的数据写入到磁盘文件。

  6. 这种模式下,提交事务之后,redo log可能仅仅停留在os cache内存缓冲里,没实际进入磁盘文件,万一此时要是机器宕机了,那么os cache里的redo log就会丢失。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多