mysql无二级缓存,应用层需结合redis实现:高频读、低更新、小结果集、可接受延迟的数据适合缓存;防穿透用空值缓存或布隆过滤器,防击穿用互斥锁,防雪崩加过期时间扰动;更新时应先改mysql再删redis。

MySQL 本身没有二级缓存机制
MySQL 内部只有查询缓存(已弃用)、InnoDB 缓冲池(Buffer Pool)这类“一级”数据页缓存,它不提供类似 MyBatis 那种可配置的二级缓存抽象层。所谓“利用二级缓存思想”,本质是应用层主动设计缓存策略,让 MySQL 和 Redis 各司其职:MySQL 负责强一致性、事务、复杂查询;Redis 负责高频、低一致性要求的读路径加速。
什么时候该把数据扔进 Redis?
不是所有表都适合缓存。重点看访问模式和更新频率:
-
SELECT极其频繁但UPDATE/INSERT很少(如配置表、省份字典、商品类目) - 结果集小、结构扁平(避免缓存大 JSON 或关联多张表的复杂视图)
- 能接受秒级甚至分钟级的数据延迟(比如用户积分余额不适合,但首页推荐位可以)
- 有明确的缓存 key 命名逻辑,且 key 可被业务代码稳定构造(如
"user:profile:{uid}")
缓存穿透、击穿、雪崩怎么防?
这三个问题都源于 Redis 没命中后直接打到 MySQL,但诱因不同:
-
穿透:查根本不存在的 ID(如
"user:profile:999999999"),每次都会穿透到 DB。对策:对空结果也缓存(SET user:profile:999999999 "" EX 60),或用布隆过滤器前置拦截 -
击穿:热点 key 过期瞬间大量请求涌进来。对策:加互斥锁(
SETNX+ 过期时间),或设置永不过期 + 主动刷新 -
雪崩:大批 key 同时过期。对策:过期时间加随机扰动(如
EX 3600 + RAND() * 600),或按业务分组错峰过期
更新时,先删 Redis 还是先改 MySQL?
绝大多数场景下,**先更新 MySQL,再删除 Redis key**。原因很实际:
- 如果先删 Redis,更新 MySQL 失败,那缓存是空的,下次读就会穿透,还可能写入脏空值
- 如果先更新 MySQL 成功、再删 Redis 失败,最多是短暂读到旧缓存,影响小且可重试
- 不要用“更新 Redis”代替“删除 Redis”——容易因并发导致新旧值覆盖错乱
- 异步删缓存更稳妥(比如用 Binlog 监听 + 消费者),但增加架构复杂度;简单服务直接同步删即可
真正难处理的是 MySQL 主从延迟 + 缓存删除时机不一致带来的短暂不一致,这没法靠顺序完全解决,得靠监控 + 降级预案兜底。










