在 Java 后端项目里,Redis 几乎是绕不开的技术。
很多人刚开始学 Redis 时,只知道它“快”“可以做缓存”,但到了面试或者项目落地时,问题就会变得更具体:
- Redis 到底是什么?
- 为什么项目里要用 Redis?
- Redis 为什么这么快?
- Redis 单线程为什么还能抗高并发?
- String、Hash、List、Set、ZSet 分别适合什么场景?
- 缓存穿透、击穿、雪崩有什么区别?
- Redis 和 MySQL 一起用时,查询流程是什么?
这篇文章就按 Java 后端常见面试和项目使用场景,把 Redis 的基础知识系统梳理一遍。
一、Redis 是什么?
Redis 是一个基于内存的高性能 Key-Value 数据库,也属于 NoSQL 数据库的一种。
它的读写性能很高,并且支持多种数据结构,所以在后端项目中经常用来做:
| 场景 | 说明 |
|---|---|
| 缓存 | 缓存热点数据,减少 MySQL 压力 |
| 分布式锁 | 控制分布式系统中的并发操作 |
| 计数器 | 点赞数、阅读数、访问量 |
| 排行榜 | 用户积分榜、热搜榜 |
| 验证码 | 短时间保存短信验证码 |
| 限流 | 控制接口访问频率 |
| 消息队列 | 简单异步任务 |
| Session 共享 | 多服务之间共享登录状态 |
面试可以这样回答:
Redis 是一个基于内存的 NoSQL 数据库,读写性能很高,支持多种数据结构,常用于缓存热点数据、分布式锁、限流、排行榜等场景。
二、为什么项目里要用 Redis?
MySQL 更适合存储核心业务数据,但如果所有高并发读请求都直接打到 MySQL,数据库压力会很大。
比如商品详情页:
10000 个请求都查询同一个商品
如果每次都查 MySQL,压力会非常高。
加上 Redis 后,流程变成:
请求 -> Redis Redis 有数据 -> 直接返回 Redis 没数据 -> 查询 MySQL -> 写入 Redis -> 返回
这样热点数据大部分请求都可以从 Redis 返回。

Redis 主要解决三个问题:
减少 MySQL 压力 提升接口响应速度 承载高并发读请求
三、Redis 为什么快?
Redis 快,常见原因有 4 个。
| 原因 | 说明 |
|---|---|
| 基于内存 | 大多数操作都在内存中完成 |
| 单线程执行命令 | 避免频繁线程切换和锁竞争 |
| IO 多路复用 | 一个线程可以处理大量连接 |
| 数据结构高效 | 内部结构针对不同场景做了优化 |
需要注意的是:
Redis 的“单线程”主要指 命令执行是单线程,不是整个 Redis 只有一个线程。
面试可以这样答:
Redis 快主要是因为数据在内存中,命令执行模型简单,采用单线程避免锁竞争,并使用 IO 多路复用处理网络连接。
四、Redis 单线程为什么还能支持高并发?
因为 Redis 的操作大多数是内存操作,本身执行速度非常快。
同时 Redis 使用 IO 多路复用,一个线程可以同时监听多个客户端连接。
简单理解:
客户端1 \ 客户端2 -> IO 多路复用 -> Redis 单线程执行命令 客户端3 /
流程图如下:

它不需要为每个连接都创建一个线程,也能处理大量请求。
不过也正因为命令执行主要是单线程,所以要避免执行耗时命令,比如大 key 删除、全量扫描等,否则可能阻塞后续请求。
五、Redis 是不是所有操作都是单线程?
不是。
早期 Redis 的核心命令执行是单线程,但后续版本引入了一些后台线程,例如:
异步删除 持久化 网络 IO 处理优化
不过在面试中可以这样表达:
Redis 的命令执行主要是单线程,所以单条命令要避免执行太久,否则会阻塞后续请求。
这句话比较稳,不会把 Redis 简单说成“完全单线程”。
六、Redis 常见数据结构有哪些?
Redis 最常见的 5 种基础数据结构是:
String、Hash、List、Set、ZSet
除此之外,还有:
Bitmap、HyperLogLog、Stream、Geo
对于实习和初中级面试来说,先把五种基础结构和对应场景掌握好就够用了。
七、String 类型适合什么场景?
String 是 Redis 最基础的数据类型,可以存字符串、数字、JSON 字符串。
常见场景:
| 场景 | 示例 |
|---|---|
| 验证码 | 短时间保存短信验证码 |
| Token | 登录状态 |
| 缓存对象 JSON | 商品详情、用户信息 |
| 计数器 | 点赞数、阅读数 |
| 分布式锁 | 使用 set nx ex |
验证码示例:
key: login:code:13800138000 value: 739421 expire: 5 分钟
计数器示例:
incr article:read:1001
incr 是原子操作,适合阅读数、点赞数这类计数场景。
八、Hash 类型适合什么场景?
Hash 类似 Java 里的 Map,适合存对象的多个字段。
例如:
key: user:1001 field: name value: 张三 field: age value: 20 field: city value: 北京
修改某个字段:
hset user:1001 age 21
相比直接存 JSON,Hash 的好处是可以单独修改某个字段,不需要把整个对象反序列化再写回去。
适合场景:
用户对象 商品对象 购物车信息 配置项
九、List 类型适合什么场景?
List 是有序列表,可以从两端插入和弹出。
常见场景:
| 场景 | 说明 |
|---|---|
| 简单消息队列 | 左进右出或右进左出 |
| 最新动态 | 按插入顺序保存 |
| 任务列表 | 保存待处理任务 |
示例:
lpush queue:order task1 rpop queue:order
不过要注意:
如果项目里真正要做消息队列,更推荐使用 RabbitMQ、RocketMQ、Kafka 这类专业 MQ。
Redis List 可以做简单队列,但可靠性、确认机制、堆积处理等能力不如专业 MQ 完整。
十、Set 类型适合什么场景?
Set 是无序不重复集合。
常见场景:
用户标签 点赞去重 共同好友 黑名单 抽奖去重
比如文章点赞:
sadd article:like:1001 user:1 sadd article:like:1001 user:2
判断用户是否点过赞:
sismember article:like:1001 user:1
Set 的核心特点就是天然去重。
比如一个用户重复点赞,Set 中也只会保存一份。
十一、ZSet 类型适合什么场景?
ZSet 是有序集合,每个元素都有一个分数 score。
常见场景:
| 场景 | 说明 |
|---|---|
| 排行榜 | 按积分、热度排序 |
| 热搜榜 | 按搜索次数排序 |
| 延迟队列 | score 存执行时间 |
| 权重排序 | 按权重取数据 |
排行榜示例:
zadd rank:score 100 user1
zadd rank:score 200 user2
zrevrange rank:score 0 9
zrevrange rank:score 0 9 可以取出分数最高的前 10 名。
面试里如果问 Redis 排行榜,基本就是回答 ZSet。
十二、Redis 缓存对象一般怎么设计 key?
Redis 的 key 要有业务含义,并且层次清晰。
常见写法:
user:1001
product:detail:2001
order:list:user:1001
login:code:13800138000
不建议使用这种随意的 key:
abc123、data001、test_key
好的 key 有几个好处:
方便排查问题 方便设置过期时间 方便按业务维度管理 方便多人协作维护
一般可以按这个格式设计:
业务名:数据类型:唯一标识
例如:
product:detail:2001
十三、缓存数据一般要不要设置过期时间?
一般建议设置。
如果不设置过期时间,Redis 中的数据可能越来越多,最终占满内存。
常见过期时间参考:
| 数据类型 | 过期时间 |
|---|---|
| 验证码 | 5 分钟 |
| 登录 Token | 7 天 |
| 商品详情缓存 | 30 分钟 |
| 首页推荐 | 5 分钟 |
| 热点榜单 | 几分钟到几十分钟 |
当然,不是所有 key 都必须过期。
比如某些长期有效的配置缓存,可以不过期,但要有主动更新机制。
过期时间一定要结合业务决定,而不是所有数据都统一设置一个时间。
十四、什么是缓存穿透?
缓存穿透指的是:
查询一个 Redis 和 MySQL 都不存在的数据,导致每次请求都会打到 MySQL。
比如恶意请求:
product_id = -1 product_id = 999999999
流程是:
查 Redis:没有 查 MySQL:也没有 不写缓存 下次再来:还是查 MySQL
如果大量这种请求进来,MySQL 压力会非常大。

十五、缓存穿透怎么解决?
常见方案有三种:
| 方案 | 说明 |
|---|---|
| 缓存空值 | MySQL 查不到时,也把空结果写入 Redis |
| 布隆过滤器 | 提前判断数据是否可能存在 |
| 参数校验 | 过滤明显非法的请求参数 |
缓存空值示例:
key: product:999999
value: null
expire: 1 分钟
这样下次同样请求过来,就可以直接从 Redis 返回空,不会继续打到 MySQL。
布隆过滤器流程:

布隆过滤器适合数据量较大、非法请求较多的场景。
十六、什么是缓存击穿?
缓存击穿指的是:
某个热点 key 过期的一瞬间,大量请求同时打到 MySQL。
比如热门商品:
product:detail:1001
平时请求都走 Redis。
突然这个 key 过期了,10000 个请求同时发现 Redis 没有,于是一起去查 MySQL。
结果就是数据库压力瞬间暴涨。
缓存击穿的关键点是:
一个热点 key 失效
十七、缓存击穿怎么解决?
常见方案:
| 方案 | 说明 |
|---|---|
| 热点 key 不设置过期时间 | 后台异步刷新缓存 |
| 互斥锁 | 只允许一个请求查库并重建缓存 |
| 逻辑过期 | 缓存不过期,数据中保存逻辑过期时间 |
互斥锁思路:

这样不会让所有请求同时打到 MySQL。
逻辑过期常用于热点数据:
Redis key 本身不过期,但 value 中带一个过期时间。发现逻辑过期后,由一个线程异步刷新缓存,其他请求先返回旧数据。
十八、什么是缓存雪崩?
缓存雪崩指的是:
大量缓存 key 在同一时间失效,导致请求集中打到 MySQL。
比如很多 key 都设置了同样的过期时间:
expire = 30 分钟
如果它们同时过期,MySQL 会突然承受大量请求。
缓存击穿和雪崩区别:
| 问题 | 特点 |
|---|---|
| 缓存击穿 | 一个热点 key 失效 |
| 缓存雪崩 | 大量 key 同时失效 |
十九、缓存雪崩怎么解决?
常见方案:
| 方案 | 说明 |
|---|---|
| 过期时间加随机值 | 避免大量 key 同时过期 |
| 热点数据提前预热 | 系统启动或活动前提前加载缓存 |
| 多级缓存 | 本地缓存 + Redis |
| 限流降级 | 防止数据库被打垮 |
| Redis 高可用 | 避免 Redis 整体不可用 |
比如过期时间不要都写死 30 分钟,可以改成:
30 分钟 + 随机 0 到 5 分钟
这样可以把过期时间打散。

二十、Redis 和 MySQL 一起用时,基本查询流程是什么?
最常见的是 Cache Aside 模式,也叫旁路缓存。
查询流程:
先查 Redis Redis 有数据:直接返回 Redis 没数据:查 MySQL MySQL 查到后写入 Redis 返回结果
图解如下:

面试可以这样答:
项目中一般使用旁路缓存模式。读请求先查 Redis,缓存未命中再查 MySQL,并把结果写入 Redis。这样可以减少数据库压力,提高热点数据访问速度。
二十一、五种基础数据结构怎么选?
最后做一个小总结。
| 数据结构 | 特点 | 常见场景 |
|---|---|---|
| String | 简单 key-value | 验证码、Token、计数器、缓存 JSON |
| Hash | field-value 结构 | 用户对象、商品对象、购物车 |
| List | 有序列表,两端操作 | 简单队列、最新动态 |
| Set | 无序不重复 | 点赞去重、标签、共同好友 |
| ZSet | 不重复且带 score | 排行榜、热搜、延迟队列 |
可以用下面这个流程简单判断:

总结
Redis 可以按一条线来记:
Redis 是基于内存的高性能 Key-Value 数据库, Java 后端常用它做缓存、验证码、排行榜、计数器、分布式锁等。 Redis 快的原因主要是内存操作、单线程命令执行、IO 多路复用和高效数据结构。 String 适合验证码、计数器、缓存对象; Hash 适合对象字段; List 适合简单队列; Set 适合去重; ZSet 适合排行榜。 缓存系统常见问题有穿透、击穿、雪崩: 穿透是查不存在的数据,可以用缓存空值、布隆过滤器解决; 击穿是热点 key 失效,可以用互斥锁、逻辑过期解决; 雪崩是大量 key 同时失效,可以用随机过期时间、限流降级、多级缓存解决。
Redis 不是简单地“加一层缓存”就完事了。
真正用好 Redis,要同时考虑数据结构选择、key 设计、过期时间、缓存一致性和异常场景。掌握这些内容,再去看分布式锁、缓存更新策略、Redis 持久化和集群,就会顺很多。
📌 码字不易,技术干货深度复盘!
如果这篇文章帮你看清了 MyBatis-Plus 查询的底层底细,别忘了 点赞、关注、收藏 三连走一波!支持作者不迷路,更多底层源码干货持续输出中!🚀
让我们一起学习面试知识,拿到自己想要的offer!

698

被折叠的 条评论
为什么被折叠?



