Redis详解_数据结构_缓存_SpringBoot_分布式锁
Redis 详解:数据结构、缓存、SpringBoot、分布式锁与高并发实战
本章位置:第三阶段 Java 企业项目 + AI 助手
对应课程:Redis
前置知识:Java 集合、MySQL、SpringBoot、Maven、HTTP、事务、Git
后续衔接:若依脚手架、淘车湾项目、高并发缓存、微服务
学习目标:从零掌握 Redis 的定位、五大核心数据类型、TTL、持久化、缓存设计、缓存穿透/击穿/雪崩、双写一致性、SpringBoot 集成、Token、验证码、排行榜、分布式锁、高可用与常见排错。
一、Redis 是什么
Redis 是一个高性能、基于内存、支持多种数据结构并可持久化的 Key-Value 数据库。
最常见用途:
热点缓存
登录 Token
验证码
Session
计数器
排行榜
点赞/关注
分布式锁
限流
幂等
简单消息流
Redis 不能简单替代 MySQL。企业项目最典型的组合是:
MySQL
负责长期、结构化、可靠的业务数据
Redis
负责高性能访问、缓存和分布式协调
典型查询链路:
Browser
↓
SpringBoot
↓
Redis
├─ 命中 → 直接返回
└─ 未命中
↓
MySQL
↓
回填 Redis
二、Redis 为什么快
最重要的原因包括:
数据主要在内存
高效数据结构
事件驱动网络模型
命令逻辑较轻量
减少磁盘随机访问
不要死记:
Redis 快 = 因为单线程
更准确的理解是:Redis 的核心命令处理长期采用串行化执行模型,但现代 Redis 仍有后台线程、I/O 等机制,所以不能理解成“整个 Redis 进程只有一个线程”。
三、Windows 上如何运行 Redis
Windows 学习环境推荐:
Docker
WSL
Windows 兼容实现
如果已经有 Docker,最简单:
docker run -d --name redis -p 6379:6379 redis
查看:
docker ps
进入 Redis CLI:
docker exec -it redis redis-cli
测试:
PING
返回:
PONG
说明 Redis 正常。
默认端口:
6379
四、Redis Key 基础
查看 Key 是否存在:
EXISTS user:1
删除:
DEL user:1
查看类型:
TYPE user:1
学习环境查看所有 Key:
KEYS *
生产环境不推荐随便使用 KEYS *,Key 很多时可能带来明显性能影响。更推荐:
SCAN 0 MATCH user:* COUNT 100
Key 命名建议:
业务:模块:标识
例如:
user:detail:1001
login:token:abc123
sms:code:13800000000
rank:answer:2026:09
lock:order:1001
五、TTL
TTL:
Time To Live
表示 Key 剩余存活时间。
设置:
EXPIRE user:1 60
查看:
TTL user:1
毫秒:
PTTL user:1
取消过期:
PERSIST user:1
更推荐写入时直接设置:
SET login:code:13800000000 123456 EX 300
相比:
SET key value
EXPIRE key 300
单条 SET ... EX 更好,因为“写值 + 设置过期”在一条命令中完成,避免两条命令之间程序异常导致 Key 永不过期。
过期删除主要可以理解为:
访问时发现过期 → 惰性删除
+
Redis 周期检查过期 Key → 主动删除
六、String
String 是最常用的数据类型,可以保存:
字符串
整数
浮点数字符串
JSON
二进制数据
基本命令:
SET name zhangsan
GET name
MSET name zhangsan age 20 city shenyang
MGET name age city
计数器:
SET count 0
INCR count
INCRBY count 10
DECR count
INCR 适合高并发计数,因为它本身是 Redis 原子命令。
Java 中不要这样:
GET
↓
Java count++
↓
SET
因为多个请求并发时可能丢更新。
场景:
缓存
计数器
Token
验证码
JSON 对象
七、Hash
Hash 可以类比:
Map<String, String>
例如:
user:1001
├─ name → 张三
├─ age → 20
└─ city → 沈阳
命令:
HSET user:1001 name 张三 age 20 city 沈阳
HGET user:1001 name
HMGET user:1001 name age
HGETALL user:1001
HDEL user:1001 city
HEXISTS user:1001 name
HINCRBY user:1001 score 10
适合:
对象字段
购物车
简单配置
String JSON 与 Hash 怎么选:
经常整体读写对象
→ String + JSON
经常单独修改字段
→ Hash
不要死记“Hash 一定更省内存”,实际要看对象大小、字段数量、访问方式和 Redis 版本。
八、List
List:
有序
允许重复
支持两端插入/弹出
命令:
LPUSH queue a
RPUSH queue b
LPOP queue
RPOP queue
LRANGE queue 0 -1
LLEN queue
可以实现简单队列:
生产:RPUSH
消费:LPOP
也可以使用阻塞命令:
BLPOP queue 30
BRPOP queue 30
但 List 不等于专业 MQ。关键业务消息通常还需要:
消费确认
重试
死信
消费组
更完整持久化语义
复杂业务更适合 RabbitMQ / RocketMQ / Kafka 等。
九、Set
Set:
无序
元素不重复
命令:
SADD user:1001:tags Java Spring Redis
SMEMBERS user:1001:tags
SISMEMBER user:1001:tags Java
SREM user:1001:tags Redis
SCARD user:1001:tags
集合运算:
SINTER a b
SUNION a b
SDIFF a b
适合:
点赞
标签
关注关系
共同关注
去重
点赞设计:
SADD article:1001:likes user:2001
SISMEMBER article:1001:likes user:2001
SCARD article:1001:likes
十、ZSet
Sorted Set / ZSet:
Member 不重复
每个 Member 有 Score
按 Score 排序
命令:
ZADD rank 100 user1
ZADD rank 80 user2
ZADD rank 120 user3
ZINCRBY rank 10 user1
ZSCORE rank user1
排行榜:
ZREVRANGE rank 0 9 WITHSCORES
查询排名:
ZREVRANK rank user1
Redis 排名从 0 开始,页面通常显示:
rank + 1
场景:
排行榜
热度榜
积分榜
按权重排序
月榜可以设计:
rank:answer:2026:09
周榜:
rank:answer:2026:week:37
十一、其他数据类型
Bitmap:
签到
在线状态
布尔状态统计
HyperLogLog:
UV 等近似基数统计
Geo:
附近门店
经纬度搜索
Stream:
消息流
消费组
Pending
当前课程优先掌握:
String
Hash
List
Set
ZSet
十二、Redis 原子性、事务、Lua、Pipeline
很多单条 Redis 命令是原子的,例如:
INCR
HINCRBY
SET ... NX
Redis 事务核心命令:
MULTI
EXEC
DISCARD
WATCH
注意:
Redis Transaction
不等于 MySQL Transaction
不要想当然认为任何执行错误都会像 MySQL 一样自动整体回滚。
WATCH 可以理解为:
乐观锁
如果执行 EXEC 前被监视的 Key 已被别人修改,事务可以放弃。
Lua 脚本适合把多条 Redis 操作在服务端一次执行,常见场景:
分布式锁解锁
库存判断 + 扣减
限流
幂等校验
Pipeline:
主要减少客户端与 Redis 的网络往返 RTT
它不是事务。
十三、持久化:RDB 和 AOF
Redis 数据主要在内存,因此需要考虑重启恢复。
RDB:
定期生成数据快照
优点:
文件紧凑
恢复速度通常较快
适合备份
缺点:
快照之间可能丢失最近一段数据
AOF:
记录写操作
重启时重放
优点:
可获得更小的数据丢失窗口
缺点:
文件更大
写入和重写有额外开销
企业系统根据:
性能
恢复目标
数据重要性
选择 RDB、AOF 或组合。
如果 Redis 只是缓存,最好设计成:
Redis 数据丢失后
仍能从 MySQL 重建
十四、缓存是什么
缓存的目标:
降低数据库压力
降低接口响应时间
最常见 Cache Aside:
查询 Redis
├─ 命中 → 返回
└─ 未命中
↓
查 MySQL
↓
写 Redis
↓
返回
伪代码:
public UserVO getUser(Long id) {
String key =
"user:detail:"
+ id;
UserVO cache =
userCacheService.get(
key
);
if (cache != null) {
return cache;
}
User user =
userMapper.selectById(
id
);
if (user == null) {
return null;
}
UserVO result =
convert(user);
userCacheService.set(
key,
result
);
return result;
}
十五、缓存穿透
缓存穿透:
请求数据库根本不存在的数据
例如一直请求:
userId=-1
userId=999999999
每次:
Redis Miss
↓
MySQL 也没有
数据库仍不断被访问。
解决:
参数校验
缓存空值
Bloom Filter
缓存空值示例:
user:detail:999
→ 特殊 NULL 标记
TTL 2 分钟
空值 TTL 通常较短,避免新数据创建后仍长时间被旧空缓存挡住。
Bloom Filter:
判断结果:
一定不存在
或
可能存在
存在一定误判率。
十六、缓存击穿
缓存击穿:
一个极热点 Key 突然失效
大量请求同时:
Redis Miss
↓
MySQL
例如:
爆款商品详情
首页热门配置
常见解决:
互斥重建
逻辑过期
热点预热
互斥重建:
Cache Miss
↓
抢锁
├─ 成功
│ ↓
│ 查 DB
│ ↓
│ 写 Cache
│ ↓
│ 解锁
└─ 失败
↓
短暂等待
↓
再读 Cache
逻辑过期:
Redis Key 不真正立即删除
Value 内保存 expireTime
过期后:
当前请求可暂时返回旧值
后台线程重建
适合:
允许短暂旧数据的极热点场景
不适合:
余额
强权限变更
强一致库存
十七、缓存雪崩
缓存雪崩:
大量 Key 同时失效
或 Redis 整体不可用
导致:
大量请求打到数据库
解决:
TTL 加随机值
缓存预热
Redis 高可用
限流
熔断
降级
例如:
30 分钟
+
随机 0~5 分钟
让过期时间打散。
三大问题记忆:
穿透
→ 不存在的数据
击穿
→ 一个热点 Key
雪崩
→ 大量 Key / Redis 整体
十八、Hot Key 与 Big Key
Hot Key:
访问量远高于其他 Key
风险:
单节点 CPU / 网络热点
失效时容易击穿
Big Key:
一个 Key 的 Value 特别大
或集合元素特别多
例如:
几十 MB String
百万字段 Hash
百万元素 List
风险:
网络传输慢
删除耗时
内存分布不均
阻塞时间增加
复制压力增大
不要:
HGETALL 超大 Hash
LRANGE huge-list 0 -1
SMEMBERS 超大 Set
需要考虑:
分页
SCAN / HSCAN / SSCAN / ZSCAN
重新拆 Key
十九、缓存一致性
假设:
MySQL User
+
Redis User Cache
用户修改昵称。
常见 Cache Aside 写策略:
先更新数据库
再删除缓存
为什么不是直接更新缓存?
因为并发下可能出现:
旧值覆盖新值
删除缓存后:
下一次读取 Cache Miss
↓
查最新 DB
↓
重建 Cache
但要理解:
数据库 + Redis
不是天然强一致事务
仍存在并发和失败窗口。
常见增强:
TTL 兜底
消息重试
延迟双删
Canal 监听 Binlog
版本号
不能只背:
“更新 DB 再删 Redis 就百分百一致”
二十、Spring @Transactional 与 Redis
不要以为:
@Transactional
可以让:
MySQL + Redis
自动成为一个强一致分布式事务。
数据库和 Redis 是:
两个独立资源系统
尤其注意:
数据库事务还没提交
就提前写 Redis
如果数据库最终回滚:
Redis 不会自动跟着回滚业务缓存
因此缓存更新要认真考虑:
事务提交时机
二十一、SpringBoot 集成 Redis
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
现代 Spring Boot 配置:
spring:
data:
redis:
host: localhost
port: 6379
database: 0
有密码:
spring:
data:
redis:
host: localhost
port: 6379
database: 0
password: your_password
旧教程可能看到:
spring.redis.*
新项目应优先检查当前 Spring Boot 官方配置;现代版本常用:
spring.data.redis.*
Spring Boot 的 Redis Starter 默认通常使用:
Lettuce
也支持:
Jedis
学习阶段保持默认 Lettuce 即可。
二十二、RedisTemplate 与 StringRedisTemplate
Spring Data Redis 核心:
RedisTemplate<K,V>
StringRedisTemplate
StringRedisTemplate:
Key / Value 都按 String 处理
默认字符串序列化
CLI 中更容易读
初学非常推荐。
注入:
@Service
public class RedisDemoService {
private final StringRedisTemplate
redisTemplate;
public RedisDemoService(
StringRedisTemplate redisTemplate
) {
this.redisTemplate =
redisTemplate;
}
}
String:
redisTemplate
.opsForValue()
.set(
"name",
"zhangsan"
);
读取:
String value =
redisTemplate
.opsForValue()
.get(
"name"
);
TTL:
redisTemplate
.opsForValue()
.set(
"login:code:13800000000",
"123456",
Duration.ofMinutes(5)
);
二十三、Spring Data Redis 操作对应
String:
redisTemplate.opsForValue()
Hash:
redisTemplate.opsForHash()
List:
redisTemplate.opsForList()
Set:
redisTemplate.opsForSet()
ZSet:
redisTemplate.opsForZSet()
例如 Hash:
redisTemplate
.opsForHash()
.put(
"user:1001",
"name",
"张三"
);
Set:
redisTemplate
.opsForSet()
.add(
"article:1001:likes",
"user:1"
);
ZSet:
redisTemplate
.opsForZSet()
.incrementScore(
"user:rank",
"user:1",
10
);
二十四、Redis 序列化
Redis 实际存的是:
字节
Java Object 需要:
序列化
Spring Data Redis 的通用 RedisTemplate 默认配置可能使用 Java 原生序列化,CLI 中可能看到:
二进制乱码样式
而且 Java 原生反序列化对不可信数据存在安全风险。
常见工程方案:
Key
→ StringRedisSerializer
Value
→ JSON
学习阶段最容易理解的方式:
ObjectMapper
对象 → JSON String
↓
StringRedisTemplate
写入:
String json =
objectMapper
.writeValueAsString(
userVO
);
redisTemplate
.opsForValue()
.set(
key,
json,
Duration.ofMinutes(
30
)
);
读取:
String json =
redisTemplate
.opsForValue()
.get(
key
);
UserVO result =
objectMapper
.readValue(
json,
UserVO.class
);
二十五、缓存 Key 设计
推荐集中管理:
public final class RedisKeys {
private RedisKeys() {
}
public static String userDetail(
Long userId
) {
return "user:detail:"
+ userId;
}
public static String loginToken(
String token
) {
return "login:token:"
+ token;
}
}
不要在 Controller / Service 到处:
手写字符串
企业缓存设计最好明确:
Key
Value Type
TTL
数据来源
什么时候写
什么时候删
是否允许旧数据
Redis 故障如何处理
二十六、用户详情缓存实战
查询:
GET /users/{id}
↓
Redis
├─ Hit → 返回
└─ Miss
↓
MySQL
├─ 不存在 → 缓存空值
└─ 存在 → JSON + TTL
更新:
@Transactional
UPDATE MySQL
↓
事务成功
↓
DELETE user:detail:{id}
下次查询:
重新回填最新缓存
二十七、Spring Cache
Spring 提供缓存抽象:
@Cacheable
@CacheEvict
@CachePut
例如:
@Cacheable(
cacheNames = "user",
key = "#id"
)
public UserVO getUser(
Long id
) {
...
}
更新后删除:
@CacheEvict(
cacheNames = "user",
key = "#id"
)
public void updateUser(
Long id,
UserUpdateDTO dto
) {
...
}
优点:
代码简洁
缺点:
复杂缓存击穿
逻辑过期
自定义锁
复杂失效
时不一定够灵活。
学习顺序:
先理解 RedisTemplate
再学缓存注解
二十八、Redis Token 登录
一种典型登录方案:
用户名密码
↓
MySQL 校验
↓
生成随机 Token
↓
Redis:
login:token:{token}
→ UserSession JSON
↓
TTL 30 分钟
↓
返回 Token
请求:
Authorization: Bearer token
↓
Interceptor / Filter
↓
Redis GET
↓
有 Session → 登录有效
无 → 401
退出:
DEL login:token:{token}
滑动过期:
每次有效访问
适当刷新 TTL
高并发系统可避免每个请求都刷新,减少额外写流量。
二十九、Redis 验证码
Key:
login:code:{phone}
Value:
123456
TTL:
5 分钟
发送频率限制:
sms:send:limit:{phone}
通过:
SET NX EX 60
做到:
60 秒内只能发送一次
注意:
前端倒计时不是安全限制
用户可以绕过前端直接调用 API,所以真正限制必须在后端。
验证码校验成功后建议:
立即 DEL
做到一次性使用。
三十、ZSet 排行榜实战
积分增加:
redisTemplate
.opsForZSet()
.incrementScore(
"rank:answer:2026:09",
String.valueOf(
userId
),
10
);
Top 10:
redisTemplate
.opsForZSet()
.reverseRangeWithScores(
"rank:answer:2026:09",
0,
9
);
当前用户排名:
Long rank =
redisTemplate
.opsForZSet()
.reverseRank(
"rank:answer:2026:09",
String.valueOf(
userId
)
);
页面:
rank + 1
重要业务最好:
MySQL 保存积分记录
Redis 提供排行榜
三十一、分布式锁为什么需要 Redis
单机:
synchronized
ReentrantLock
只能控制:
一个 JVM
多实例:
Server A
Server B
Server C
每台 JVM:
都有自己的本地锁
所以需要:
共享的锁服务
Redis 就可以作为一种实现。
三十二、错误的 Redis 锁
错误方案:
SETNX lock:key 1
问题:
应用崩溃
锁永远存在
继续改:
SETNX lock:key 1
EXPIRE lock:key 30
仍有问题:
两条命令
如果 SETNX 成功后程序崩溃:
EXPIRE 没执行
仍可能死锁。
三十三、基础正确加锁
使用一条命令:
SET lock:order:1001 uuid-A NX EX 30
含义:
Key 不存在才设置
+
30 秒过期
+
Value 是当前客户端唯一标识
为什么 Value 不能固定为 1?
场景:
A 获得锁
↓
A 执行业务超过 30 秒
↓
锁过期
↓
B 获得新锁
↓
A 执行结束
↓
A DEL
如果 Value 一样:
A 可能误删 B 的锁
三十四、为什么解锁必须原子
错误 Java:
GET lock
↓
判断 value 是自己的
↓
DEL lock
GET 和 DEL 之间:
锁可能过期
另一个客户端获得新锁
然后旧客户端:
误删新锁
所以要用 Lua:
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
把:
比较
+
删除
作为一个原子操作。
三十五、锁续期与 Watchdog
如果正常业务时间:
不确定
固定 TTL 可能:
业务还没执行完
锁先过期
成熟客户端会考虑:
自动续期
例如 Redisson:
Watchdog
在持锁线程正常工作时:
自动延长锁 TTL
三十六、Redisson
Redisson 是常用 Redis Java 客户端,提供:
RLock
RMap
RSet
Semaphore
分布式锁示意:
RLock lock =
redissonClient
.getLock(
"lock:order:"
+ orderId
);
boolean locked =
lock.tryLock();
try {
if (!locked) {
throw new BusinessException(
"操作处理中"
);
}
// business
} finally {
if (
locked
&&
lock.isHeldByCurrentThread()
) {
lock.unlock();
}
}
真实项目优先成熟库,不要每个项目复制一份自己实现的 RedisLockUtil。
三十七、分布式锁不是万能保证
非常关键的业务仍应考虑:
数据库唯一约束
幂等
事务
锁过期
网络分区
故障转移
Fencing Token
例如:
一个用户只能领取一张券
数据库仍可以有:
UNIQUE(user_id, coupon_id)
作为最后一道防线。
三十八、Redis 官方锁模型要注意什么
简单单节点锁:
SET NX EX
+
唯一 Value
+
原子解锁
适合很多普通业务协调。
但在主从故障切换、网络分区、长时间任务等情况下,要认真考虑:
锁的安全性
Redis 官方还讨论 Redlock 和 fencing token 等问题。
因此:
不能把“Redis 锁”理解成绝对不会出错
三十九、限流
简单固定窗口:
Key:
rate:user:1001:202609101900
每请求:
INCR
第一次设置:
60 秒 TTL
超过:
100
拒绝。
缺点:
窗口边界可能瞬间双倍
更高级:
滑动窗口
令牌桶
漏桶
可以结合 Redis + Lua。
四十、幂等
用户连续点击:
提交订单
可能产生:
重复请求
一种方案:
生成一次性幂等 Token
↓
Redis 保存
↓
提交时 Lua 原子校验 + 删除
不能:
GET
↓
DEL
分两步,否则并发不安全。
四十一、Pub/Sub 与 Stream
Pub/Sub:
实时广播
如果消费者不在线:
消息可能直接错过
适合:
轻量通知
不适合:
必须可靠消费的关键业务
Redis Streams:
消息 ID
消费组
Pending
能力更完整,但复杂业务仍应根据需求和 RabbitMQ / RocketMQ / Kafka 比较。
四十二、主从、Sentinel、Cluster
Replication:
Master
↓
Replica
作用:
数据副本
读扩展
高可用基础
复制通常存在:
异步延迟
Sentinel:
监控主从
故障检测
自动 Failover
发现新主节点
Cluster:
数据分片
+
高可用
Key 会映射到:
Hash Slot
再分配到多个节点。
学习顺序:
单机
↓
主从
↓
Sentinel
↓
Cluster
四十三、Redis 安全
生产不要:
6379 直接暴露公网
应考虑:
内网
防火墙
ACL
密码/用户
TLS
最小权限
不要把生产 Redis 密码提交到 Git。
危险命令:
FLUSHALL
FLUSHDB
KEYS *
CONFIG
DEBUG
都需要谨慎。
四十四、Redis 监控
常关注:
内存
命中率
连接数
OPS
Slowlog
Evicted Keys
复制延迟
Hot Key
Big Key
查看:
INFO
INFO memory
INFO stats
慢日志:
SLOWLOG GET
Redis 不是所有命令都是 O(1)。
例如:
GET
通常近 O(1)
HGET
通常近 O(1)
HGETALL
O(N)
SMEMBERS
O(N)
N 很大时仍可能慢。
四十五、常见报错排查
1. Connection refused
检查:
Redis 是否启动
host
port
Docker 端口映射
password
防火墙
2. Docker 里 SpringBoot 连接 localhost 失败
如果 SpringBoot 也在容器中:
localhost
指:
当前 SpringBoot 容器自己
不是 Redis 容器。
Docker Compose 服务之间应考虑:
redis:6379
3. Redis CLI 有 Key,SpringBoot 查不到
检查:
database index
Redis 地址
Key 前缀
序列化
环境
4. CLI 看到乱码
常见:
JDK Serialization
使用:
StringRedisTemplate
或 String Key + JSON Value
5. 缓存命中但数据旧
检查:
更新 DB 后是否删除缓存
TTL
事务提交时机
不同环境 Key
6. 内存一直涨
检查:
TTL
Key 数量
Big Key
历史排行榜
缓存是否只增不删
四十六、Redis Key 设计文档示例
名称:
用户详情缓存
Key:
user:detail:{userId}
Value:
UserVO JSON
TTL:
30~35 分钟随机
数据源:
MySQL sys_user
读取:
Cache Aside
回填:
Cache Miss 后查 DB
失效:
用户更新成功后删除
不存在数据:
空值缓存 2 分钟
一致性:
最终一致
故障:
Redis 异常时按限流策略降级 MySQL
真正做企业缓存设计时,不能只写:
“使用 Redis 优化性能”
而应明确:
缓存什么
为什么缓存
Key 是什么
TTL 多久
什么时候删
Redis 挂了怎么办
四十七、Redis 与前面知识的关系
Redis + SpringBoot:
starter
↓
AutoConfiguration
↓
RedisConnectionFactory
↓
RedisTemplate
Redis + MySQL:
Redis Cache
↓ Miss
MySQL
Redis + Maven:
spring-boot-starter-data-redis
↓
Spring Data Redis
↓
Lettuce
Redis + 事务:
MySQL Transaction
≠
Redis Transaction
Redis + 多实例:
synchronized
只能 JVM 内
Redis Lock
可做跨实例协调
Redis + Vue:
Vue
不能直接访问 Redis
Vue
↓
SpringBoot API
↓
Redis
四十八、练习清单
- Docker 启动 Redis,执行
PING。 - 使用 String 完成
SET/GET/INCR/EXPIRE/TTL。 - 使用 Hash 保存用户字段。
- 使用 List 实现简单队列。
- 使用 Set 实现点赞和去重。
- 使用 ZSet 实现 Top 10 排行榜。
- 创建 SpringBoot 项目并引入
spring-boot-starter-data-redis。 - 使用
StringRedisTemplate完成 String/Hash/Set/ZSet 操作。 - 用 ObjectMapper + JSON 缓存
UserVO。 - 实现用户详情 Cache Aside。
- 为不存在用户增加空值缓存。
- 修改用户后删除缓存。
- 实现 Redis Token 登录状态。
- 实现验证码 5 分钟过期。
- 用
SET NX EX实现发送验证码 60 秒限频。 - 用 ZSet 实现月榜。
- 使用
SET NX EX + UUID + Lua实现基础分布式锁。 - 模拟热点 Key 缓存击穿。
- 用互斥锁实现缓存重建。
- 给批量缓存增加随机 TTL。
- 使用
SCAN查找指定前缀 Key。 - 使用
SLOWLOG GET理解慢命令。 - 体验 Pipeline 与普通循环的网络差异。
- 学习 RDB/AOF 配置与重启恢复。
- 用 Redis Insight 辅助查看数据,但同时坚持会用 redis-cli。
四十九、常见面试题
1. Redis 为什么快?
数据主要在内存,
使用高效数据结构和事件驱动网络模型,
很多命令实现较轻量。
不能只回答“因为单线程”。
2. Redis 五大基本类型?
String
Hash
List
Set
ZSet
3. 穿透、击穿、雪崩区别?
穿透:
查不存在的数据
击穿:
一个热点 Key 失效
雪崩:
大量 Key 或 Redis 大面积失效
4. 为什么更新 DB 后删除缓存?
Cache Aside 常见写策略。
删除缓存后下一次读取重新从 DB 加载,
比直接并发更新 DB 和缓存更容易控制一致性。
5. 为什么不能保证绝对一致?
MySQL 和 Redis 是两个独立系统,
存在并发、失败和事务时序窗口。
6. Redis 分布式锁基本方案?
SET key uniqueValue NX EX ttl
+
Lua compare-and-delete
7. 为什么不能 SETNX 再 EXPIRE?
两条命令之间可能崩溃,
导致锁永久存在。
8. 为什么解锁不能 GET 后 DEL?
两条命令不原子,
可能误删别人刚获得的新锁。
9. RDB 和 AOF?
RDB:快照
AOF:写命令日志
10. RedisTemplate 与 StringRedisTemplate?
RedisTemplate 更通用,
StringRedisTemplate 专门针对 String,
默认字符串序列化,更易调试。
11. 为什么生产不建议 KEYS *?
Key 多时一次扫描可能影响 Redis 响应,
推荐使用 SCAN。
12. ZSet 为什么适合排行榜?
Member 唯一,
每个 Member 有 Score,
Redis 按 Score 维护排序。
13. Set 为什么适合点赞?
Member 不重复,
天然可以用 userId 去重。
14. Pipeline 与事务区别?
Pipeline 主要优化网络 RTT,
Transaction 提供命令批量顺序执行语义。
15. Sentinel 与 Cluster?
Sentinel 更偏主从高可用和 Failover;
Cluster 同时解决分片容量扩展和高可用。
五十、必须掌握的命令
Key:
EXISTS DEL TYPE EXPIRE TTL PTTL PERSIST SCAN
String:
SET GET MSET MGET INCR DECR INCRBY
Hash:
HSET HGET HMGET HGETALL HDEL HEXISTS HINCRBY
List:
LPUSH RPUSH LPOP RPOP LRANGE LLEN BLPOP BRPOP
Set:
SADD SREM SMEMBERS SISMEMBER SCARD SINTER SUNION SDIFF
ZSet:
ZADD ZINCRBY ZRANGE ZREVRANGE ZRANK ZREVRANK ZSCORE
Transaction:
MULTI EXEC DISCARD WATCH
Monitoring:
INFO SLOWLOG
五十一、必须掌握的 Spring Data Redis
spring-boot-starter-data-redis
spring.data.redis.*
RedisConnectionFactory
RedisTemplate
StringRedisTemplate
opsForValue()
opsForHash()
opsForList()
opsForSet()
opsForZSet()
五十二、Redis 核心知识树
Redis
│
├─ Data Types
│ ├─ String
│ ├─ Hash
│ ├─ List
│ ├─ Set
│ └─ ZSet
│
├─ Key
│ ├─ Naming
│ ├─ TTL
│ ├─ SCAN
│ ├─ Hot Key
│ └─ Big Key
│
├─ Persistence
│ ├─ RDB
│ └─ AOF
│
├─ Atomic
│ ├─ Atomic Command
│ ├─ MULTI/EXEC
│ ├─ WATCH
│ ├─ Lua
│ └─ Pipeline
│
├─ Cache
│ ├─ Cache Aside
│ ├─ Penetration
│ ├─ Breakdown
│ ├─ Avalanche
│ ├─ Warm-up
│ └─ Consistency
│
├─ SpringBoot
│ ├─ Lettuce
│ ├─ RedisTemplate
│ ├─ StringRedisTemplate
│ └─ Serialization
│
├─ Business
│ ├─ Token
│ ├─ Verify Code
│ ├─ Ranking
│ ├─ Like
│ ├─ Rate Limit
│ └─ Idempotency
│
├─ Lock
│ ├─ SET NX EX
│ ├─ Unique Value
│ ├─ Lua Unlock
│ ├─ Watchdog
│ └─ Redisson
│
└─ High Availability
├─ Replication
├─ Sentinel
└─ Cluster
五十三、本章最终总结
Redis 最核心的五大类型:
String
Hash
List
Set
ZSet
形成条件反射:
普通缓存 / Token / 计数
→ String
对象字段
→ Hash
队列
→ List / Stream
去重
→ Set
排行榜
→ ZSet
缓存最基本链路:
Redis
↓ Miss
MySQL
↓
Redis
三大缓存问题:
穿透
→ 不存在数据
击穿
→ 一个热点 Key
雪崩
→ 大量 Key / Redis 整体
缓存一致性常见思路:
更新数据库
↓
删除缓存
↓
TTL 最终兜底
SpringBoot:
spring-boot-starter-data-redis
spring.data.redis.*
StringRedisTemplate
RedisTemplate
分布式锁:
SET NX EX
+
唯一 Value
+
Lua 解锁
+
TTL
+
续期
+
数据库约束
真正会 Redis,不是只会:
redisTemplate
.opsForValue()
.set(...)
而是知道:
为什么缓存
缓存什么
TTL 多久
什么时候失效
Redis 挂了怎么办
怎么防穿透/击穿/雪崩
怎么保证业务最终一致
为什么分布式锁可能失效
怎么避免 Big Key / Hot Key
到这里,第三阶段的:
Redis
课程单元完成。
按照课程表,下一篇进入:
使用 AI 了解若依脚手架
第一部分:POI + RBAC
后面会把前面学过的:
SpringBoot
Vue
MyBatis
Redis
RBAC
Git
真正放进若依项目中串起来。
官方学习参考
Redis 官方文档:
https://redis.io/docs/latest/
Spring Data Redis:
https://docs.spring.io/spring-data/redis/reference/
Spring Boot Redis:
https://docs.spring.io/spring-boot/reference/data/nosql.html
版本提醒:
Redis、Spring Boot、Spring Data Redis 都在持续更新。
学习核心原理时优先掌握:
数据结构
TTL
缓存
一致性
分布式锁
高可用
真正创建项目时,
具体配置项、序列化 API 和客户端版本
以当前官方文档为准。