文章目录
- [第 5 课:Redis 常见坑 & 面试高频问题()](#第 5 课:Redis 常见坑 & 面试高频问题())
-
- 一、先记住一个前提(非常重要)
- [二、坑 1:缓存不一致(面试必问 TOP 1)](#二、坑 1:缓存不一致(面试必问 TOP 1))
-
- [❓ 问题是什么?](#❓ 问题是什么?)
- [❌ 错误做法(很多新手都会写)](#❌ 错误做法(很多新手都会写))
- 为什么危险?(理解即可)
- [✅ 正确做法(标准答案)](#✅ 正确做法(标准答案))
- [🔑 标准代码模板(记住它)](#🔑 标准代码模板(记住它))
- [🧠 面试回答一句话版本](#🧠 面试回答一句话版本)
- [三、坑 2:缓存穿透(非常常见)](#三、坑 2:缓存穿透(非常常见))
-
- [❓ 什么是缓存穿透?](#❓ 什么是缓存穿透?)
- [❌ 错误理解](#❌ 错误理解)
- [✅ 常见解决方案(你现在要知道的)](#✅ 常见解决方案(你现在要知道的))
-
- [方案 1:查不到也缓存(最简单)](#方案 1:查不到也缓存(最简单))
- [方案 2:参数校验(推荐)](#方案 2:参数校验(推荐))
- [🧠 面试一句话版本](#🧠 面试一句话版本)
- [四、坑 3:缓存击穿(热点 Key 失效)](#四、坑 3:缓存击穿(热点 Key 失效))
-
- [❓ 什么是缓存击穿?](#❓ 什么是缓存击穿?)
- 典型场景
- [❌ 天真做法](#❌ 天真做法)
- [✅ 常见解决思路(知道即可)](#✅ 常见解决思路(知道即可))
-
- [方案 1:TTL 随机(最简单)](#方案 1:TTL 随机(最简单))
- [方案 2:加锁(进阶)](#方案 2:加锁(进阶))
- [🧠 面试一句话版本](#🧠 面试一句话版本)
- [五、坑 4:缓存雪崩(系统级事故)](#五、坑 4:缓存雪崩(系统级事故))
-
- [❓ 什么是缓存雪崩?](#❓ 什么是缓存雪崩?)
- 你现在要知道的解决方向(不要求实现)
- [🧠 面试一句话版本](#🧠 面试一句话版本)
- [六、坑 5:Key 设计不合理(真实项目常见)](#六、坑 5:Key 设计不合理(真实项目常见))
-
- [❌ 错误 Key 设计](#❌ 错误 Key 设计)
- [✅ 推荐 Key 设计规范(记住)](#✅ 推荐 Key 设计规范(记住))
- [七、坑 6:Redis 当数据库用(大忌)](#七、坑 6:Redis 当数据库用(大忌))
-
- [❌ 错误思想](#❌ 错误思想)
- 正确认知
- 八、你现在应该形成的"工程直觉"
- [九、Redis 面试"标准四连问"模板(送你)](#九、Redis 面试“标准四连问”模板(送你))
- [十、这一课你只需要牢牢记住 5 句话](#十、这一课你只需要牢牢记住 5 句话)
第 5 课:Redis 常见坑 & 面试高频问题()
目标:
你不仅会写缓存代码,还知道:什么时候会炸、为什么、怎么兜底
一、先记住一个前提(非常重要)
Redis 是缓存,不是数据库
👉 所以所有问题,几乎都围绕一句话:
"缓存和数据库不一致怎么办?"
二、坑 1:缓存不一致(面试必问 TOP 1)
❓ 问题是什么?
数据库里已经是新数据了,但 Redis 里还是旧的。
❌ 错误做法(很多新手都会写)
text
1. 更新数据库
2. 更新 Redis
看起来没问题,但实际上非常危险。
为什么危险?(理解即可)
- 并发请求下
- 有可能 Redis 被旧数据覆盖
- 最终 Redis 比数据库还旧
✅ 正确做法(标准答案)
更新数据库 → 删除 Redis
顺序一定是:
text
1. 更新数据库
2. 删除 Redis 缓存
🔑 标准代码模板(记住它)
java
// 1. 更新数据库
updateUser(user);
// 2. 删除缓存
stringRedisTemplate.delete("user:" + user.getId());
👉 下次请求自然会重新写缓存
🧠 面试回答一句话版本
"我用旁路缓存模式,更新数据库后删除缓存,避免并发导致的不一致问题。"
三、坑 2:缓存穿透(非常常见)
❓ 什么是缓存穿透?
查一个"数据库里根本不存在"的数据
text
userId = -1
流程变成:
text
请求 → Redis 没有
→ MySQL 没有
→ 每次都打数据库
👉 Redis 完全挡不住
❌ 错误理解
"Redis 没用啊,每次都查数据库"
❌ 不是 Redis 的问题,是你没处理"空数据"
✅ 常见解决方案(你现在要知道的)
方案 1:查不到也缓存(最简单)
bash
set user:-1 null ex 60
Java 逻辑:
java
if (dbData == null) {
redis.set(key, "null", 60);
return null;
}
方案 2:参数校验(推荐)
java
if (userId <= 0) {
return null;
}
🧠 面试一句话版本
"缓存穿透我一般通过参数校验或缓存空值来解决。"
四、坑 3:缓存击穿(热点 Key 失效)
❓ 什么是缓存击穿?
- 一个非常热门的数据
- 在某一时刻 缓存过期
- 瞬间大量请求 → 直打数据库
典型场景
text
首页配置
系统参数
热点商品
❌ 天真做法
text
缓存到期 → 所有人一起查数据库
✅ 常见解决思路(知道即可)
方案 1:TTL 随机(最简单)
java
int ttl = 300 + random.nextInt(60);
方案 2:加锁(进阶)
text
一个线程查数据库
其他线程等待
🧠 面试一句话版本
"缓存击穿一般通过给过期时间加随机值,或者加互斥锁解决。"
五、坑 4:缓存雪崩(系统级事故)
❓ 什么是缓存雪崩?
大量缓存在同一时间过期 / Redis 故障
后果:
text
Redis 挂了
→ 全部请求打数据库
→ 数据库崩
你现在要知道的解决方向(不要求实现)
- 过期时间打散
- 限流
- 熔断
- Redis 高可用
🧠 面试一句话版本
"缓存雪崩一般通过过期时间打散、限流、以及 Redis 高可用来避免。"
六、坑 5:Key 设计不合理(真实项目常见)
❌ 错误 Key 设计
text
user
- 冲突
- 不可扩展
- 不可维护
✅ 推荐 Key 设计规范(记住)
text
业务:模块:主键
示例:
text
user:info:1001
order:detail:2002
login:token:uuid
👉 Key 就是 Redis 的"表结构"
七、坑 6:Redis 当数据库用(大忌)
❌ 错误思想
"Redis 很快,那我把数据都放 Redis 吧"
正确认知
- Redis:
👉 缓存 / 临时数据 / 可丢失数据 - MySQL:
👉 核心业务数据
八、你现在应该形成的"工程直觉"
看到下面情况,你要能立刻反应:
| 情况 | 你应该想到 |
|---|---|
| 数据更新 | 删缓存 |
| 查不到数据 | 穿透 |
| 热点数据 | 击穿 |
| 大面积过期 | 雪崩 |
| Redis 挂 | 限流 |
九、Redis 面试"标准四连问"模板(送你)
Q:Redis 缓存一致性怎么保证?
A:旁路缓存,更新数据库后删除缓存。
Q:缓存穿透怎么解决?A:参数校验或缓存空值。
Q:缓存击穿呢?A:TTL 随机或加锁。
Q:缓存雪崩?A:过期时间打散 + 高可用。
👉 这 4 问,能答出来,Redis 就过关了
十、这一课你只需要牢牢记住 5 句话
- Redis 是缓存,不是数据库
- 更新数据 → 删缓存
- 查不到也要处理
- 热点数据要特殊对待
- Key 设计就是数据模型