HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
  • 《LearnJavaToFindAJob》

    • 导读

    • 【初级】6~12k档

    • 【中级】12k-26k档

      • JVM进阶

      • Java进阶

      • MySQL

        • Innodb和MyISAM索引的区别
        • MySQL-like是否可以使用索引
        • MySQL一些索引失效的场景和原理
        • MySQL大表索引重建
        • MySQL如何行转列?
        • MySQL死锁的场景
        • MySQL的架构和执行流程
        • MySQL的缓存
        • MySQL的自增ID用完了会怎样?
        • MySQL索引的分类、何时使用、何时不使用、何时失效?
        • MySQL联合索引在B+数的存储结构和最左匹配原则原理
        • MySQL连表优化
        • MySQL连表查询的原理
        • MySQL那种事务隔离级别性能高
        • Mysql的索引和主键的区别
        • binlog、redolog、undolog的区别和作用
        • 什么是前缀索引,什么情况才使用?
        • 可重复读是否能解决幻读?
        • 我以为我对Mysql事务很熟,直到我遇到了阿里面试官
        • 聊聊MySQL索引的分类和结构吧
        • 脏读、幻读
      • 中间件

      • 算法

      • 高阶

    • 【高级】26k+档

    • 大厂面试题

    • 求职建议

    • 面经

  • LearnJavaToFindAJob
  • 【中级】12k-26k档
  • MySQL
#MySQL #缓存
HaC
2026-06-25
目录

MySQL的缓存

在现代 MySQL(8.0+)中,根本没有所谓的“连表缓存结果”,底层全都是单表的数据页缓存(Buffer Pool)。只要执行 JOIN,MySQL 每次都要在内存里把这几张表的数据重新“手拉手”匹配一遍。

那么,当数据发生改变(比如执行了 UPDATE、DELETE 或 INSERT)时,MySQL 的单表缓存(Buffer Pool)是如何精准判断失效并进行更新的呢?

这背后依赖的是一套极其严密的“脏页(Dirty Page)管理”与“内存淘汰机制”。

# 一、 缓存失效的真相:并不是“直接删除”,而是标记为“脏页”

在 MySQL 的 Buffer Pool 内存中,数据是以 Page(数据页,默认 16KB) 为最小单位存储的。一个数据页里可能存放了你 users 表里的几十条用户数据。

当某行数据发生改变时,MySQL 绝对不会立刻去把这个内存页删掉,它的处理流程如下:

# 1. 内存中就地修改(瞬间完成)

当发起 UPDATE users SET name = '新名字' WHERE id = 1; 时:

  • MySQL 会先看 id=1 所在的数据页是否在 Buffer Pool 内存中。
  • 如果在,MySQL 会直接在内存中把这个页里的名字改掉。
  • 此时,内存里的数据是“最新的”,而磁盘上的数据还是“老数据”。这个内存与磁盘不一致的数据页,就被称为“脏页(Dirty Page)”。

# 2. 通过 Flush 链表进行追踪

MySQL 内部有一个专门的链表叫 Flush List(刷脏链表)。一旦某个数据页变成了脏页,它的指针就会被加入到这个链表里。

  • 对于接下来的连表查询(JOIN):由于数据在内存里已经是最新状态了,后续的 JOIN 查询直接读取这个“脏页”里的新名字,拿到的就是正确的结果。
  • 缓存没有失效,它只是变新了。

# 3. 异步刷盘(真正落盘)

MySQL 后台有专门的 Master 线程,会根据系统的空闲程度、Redo Log 的落盘进度,不慌不忙地把 Flush 链表里的“脏页”异步写入到磁盘中,让内存和磁盘达成一致。

# 二、 那么,内存什么时候会真正“失效 / 擦除”呢?

既然修改只是让缓存变新,那内存里的数据页什么时候会被彻底清理(失效)呢?这取决于内存够不够用。

Buffer Pool 的大小是有限的(由参数 innodb_buffer_pool_size 决定)。当有很多新的查询进来,内存满了装不下时,MySQL 就必须淘汰旧的缓存。它使用的是一种改进版的 LRU(Least Recently Used,最近最少使用)算法。

  1. 冷热分代:MySQL 把存放缓存页的 LRU 链表分成了两部分:5/8 的热数据区(New Sublist)**和**3/8 的冷数据区(Old Sublist)。
  2. 末位淘汰(真正的失效):当新查询需要加载新的磁盘页,而内存满了,MySQL 就会盯住冷数据区最末尾的数据页。
    • 如果这个页是干净的(没被修改过):直接从内存中无情抹去(失效),腾出空间。
    • 如果这个页是脏页(被修改过但还没写回磁盘):MySQL 会被迫触发同步刷盘,把数据写回磁盘,然后再把这个内存页抹去。

# 三、 总结:MySQL 的单表缓存判断逻辑

回到你的问题:数据改变了,缓存如何判断失效?

  • 在业务读写时:MySQL 不需要判断失效。因为数据改变是直接在缓存(内存)里改的,缓存永远保持最新。连表查询(JOIN)每次去读单表缓存,读到的都是最新修改后的数据。
  • 在内存管理时:MySQL 通过 LRU 算法的冷热分代来判断哪些单表缓存太久没人访问了。只有没人访问的旧数据页,才会被彻底踢出内存(真正意义上的缓存失效)。

这套设计非常精妙,它用“只改内存 + 异步写盘”的机制,把昂贵的磁盘 I/O 变成了极快的内存操作,从而撑起了动辄几万的并发读写。

#MySQL#缓存
上次更新: 2026-06-25 17:18:05
最近更新
01
MySQL支持的锁有哪些
06-25
02
HTTP 是不保存状态的协议, 如何保存用户状态
06-25
03
WebSocket、短轮询、长轮询的区别
06-25
更多文章>
Theme by Vdoing | Copyright © 2020-2026 HaC
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式