Redis 使用教程(含 Spring Boot 全功能示例)
目标:一份可学习、可复制、可上生产的 Redis 教程。
范围:覆盖 Redis 核心与常用高级能力,并提供 Spring Boot 项目中的落地示例。
1. Redis 是什么
Redis(Remote Dictionary Server)是内存数据结构数据库,可作为:
- 缓存(Cache)
- 数据库(KV/文档/计数等)
- 消息中间件(Pub/Sub、Stream)
- 分布式协调组件(锁、限流、去重、队列)
特点:
- 单线程事件驱动(Redis 6+ 网络 I/O 可多线程)
- 读写极快(内存操作)
- 丰富数据结构
- 支持持久化、主从、哨兵、集群
2. 安装与启动
2.1 Docker 启动(推荐)
docker run -d --name redis \
-p 6379:6379 \
redis:7.2
带密码示例:
docker run -d --name redis \
-p 6379:6379 \
redis:7.2 \
redis-server --requirepass "123456"
2.2 常用命令
redis-cli
PING
INFO
DBSIZE
FLUSHDB
3. Redis 核心概念
- key-value:所有数据都以 key 存储
- db:逻辑库(默认 16 个)
- 过期时间:可为 key 设置 TTL
- 原子性:单条命令原子执行
- 事务:
MULTI/EXEC(非强隔离)
4. 数据类型与命令示例
4.1 String(字符串)
适合:缓存对象 JSON、计数器、分布式锁标识。
SET user:1:name "tom"
GET user:1:name
INCR page:view:home
SET token:abc "v1" EX 3600 NX
MSET k1 v1 k2 v2
MGET k1 k2
4.2 Hash(哈希)
适合:对象属性(用户信息)。
HSET user:1 id 1 name tom age 20
HGET user:1 name
HGETALL user:1
HINCRBY user:1 loginCount 1
4.3 List(列表)
适合:简单消息队列、任务队列。
LPUSH queue:order o1 o2 o3
RPOP queue:order
BLPOP queue:order 10
LRANGE queue:order 0 -1
4.4 Set(集合)
适合:标签、去重、共同好友。
SADD tags:user:1 java redis spring
SMEMBERS tags:user:1
SISMEMBER tags:user:1 redis
SINTER tags:user:1 tags:user:2
4.5 ZSet(有序集合)
适合:排行榜、延迟队列、权重排序。
ZADD rank:game 100 u1 88 u2 130 u3
ZRANGE rank:game 0 9 WITHSCORES
ZREVRANGE rank:game 0 9 WITHSCORES
ZINCRBY rank:game 5 u2
4.6 Bitmap(位图)
适合:签到、活跃用户统计(节省内存)。
SETBIT sign:2026-04 user1001 1
GETBIT sign:2026-04 user1001
BITCOUNT sign:2026-04
4.7 HyperLogLog(基数统计)
适合:UV 近似去重统计。
PFADD uv:2026-04-01 user1 user2 user3
PFCOUNT uv:2026-04-01
PFMERGE uv:week uv:2026-04-01 uv:2026-04-02
4.8 Geo(地理位置)
适合:附近门店、附近的人。
GEOADD city:shop 116.397128 39.916527 shop1
GEOADD city:shop 116.405285 39.904989 shop2
GEORADIUS city:shop 116.40 39.90 5 km WITHDIST
4.9 Stream(消息流)
适合:可靠消息队列、消费组。
XADD mq:order * orderId 1001 userId 88 amount 99.9
XGROUP CREATE mq:order g1 0 MKSTREAM
XREADGROUP GROUP g1 c1 COUNT 10 STREAMS mq:order >
XACK mq:order g1 1712121212121-0
4.10 发布订阅 Pub/Sub
适合:实时通知(不保证离线消息)。
SUBSCRIBE news:tech
PUBLISH news:tech "hello redis pubsub"
5. 过期策略与淘汰策略
5.1 设置过期
SET k v EX 60
EXPIRE k 120
TTL k
PERSIST k
5.2 淘汰策略(内存满时)
常见:
noevictionallkeys-lruallkeys-lfuvolatile-lru
配置示例:
maxmemory 512mb
maxmemory-policy allkeys-lru
6. 持久化(RDB / AOF)
6.1 RDB(快照)
- 优点:恢复快,文件紧凑
- 缺点:可能丢失最近写入
save 900 1
save 300 10
save 60 10000
6.2 AOF(追加日志)
- 优点:数据更安全
- 缺点:文件更大,恢复稍慢
appendonly yes
appendfsync everysec
6.3 推荐
生产常用:RDB + AOF 同时开启。
7. 事务、Lua 脚本与 Pipeline
7.1 事务
MULTI
SET a 1
INCR a
EXEC
说明:Redis 事务不支持回滚(命令错误时局部失败)。
7.2 Lua 脚本
优点:多命令原子执行,减少网络往返。
EVAL "return redis.call('INCR', KEYS[1])" 1 counter:key
7.3 Pipeline
批量发送命令提高吞吐,不保证原子性。
8. 高可用与分布式
8.1 主从复制
- 主节点写,从节点读(可读扩展)
- 从节点默认只读
REPLICAOF 10.0.0.1 6379
8.2 Sentinel 哨兵
作用:
- 监控主从
- 自动故障转移
- 提供主节点发现
示例(sentinel.conf):
sentinel monitor mymaster 10.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
8.3 Redis Cluster
- 数据分片(16384 slots)
- 去中心化,支持横向扩展
- 客户端需支持重定向
9. 安全配置
- 绑定内网:
bind 127.0.0.1或内网 IP - 开启密码:
requirepass - 禁用高危命令(按需 rename-command)
- 开启 TLS(企业场景)
- 使用防火墙限制访问来源
10. 性能优化与排查
常用建议:
- 避免大 key、热 key
- 避免一次性读取超大集合
- 使用批量命令和 pipeline
- 监控慢查询
慢日志:
CONFIG SET slowlog-log-slower-than 10000
SLOWLOG GET 10
内存分析:
INFO memory
MEMORY USAGE key1
11. Redis 在 Spring Boot 项目中的完整使用
下面用 Spring Boot 3 + Spring Data Redis + Lettuce 示例。
11.1 依赖
pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
11.2 基础配置
application.yml:
spring:
data:
redis:
host: 127.0.0.1
port: 6379
password: 123456
database: 0
timeout: 3s
lettuce:
pool:
max-active: 16
max-idle: 8
min-idle: 2
max-wait: 2s
11.3 RedisTemplate 序列化配置
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
StringRedisSerializer keySerializer = new StringRedisSerializer();
GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
template.setKeySerializer(keySerializer);
template.setHashKeySerializer(keySerializer);
template.setValueSerializer(valueSerializer);
template.setHashValueSerializer(valueSerializer);
template.afterPropertiesSet();
return template;
}
}
11.4 String 示例(缓存/计数器)
@Service
public class StringOpsService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void setToken(String token, String userId) {
redisTemplate.opsForValue().set("token:" + token, userId, Duration.ofHours(2));
}
public String getUserIdByToken(String token) {
Object val = redisTemplate.opsForValue().get("token:" + token);
return val == null ? null : val.toString();
}
public Long incrementPageView(String page) {
return redisTemplate.opsForValue().increment("pv:" + page);
}
}
11.5 Hash 示例(对象存储)
@Service
public class UserCacheService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void cacheUser(User user) {
String key = "user:" + user.getId();
Map<String, Object> map = new HashMap<>();
map.put("id", user.getId());
map.put("name", user.getName());
map.put("age", user.getAge());
redisTemplate.opsForHash().putAll(key, map);
redisTemplate.expire(key, Duration.ofMinutes(30));
}
public Map<Object, Object> getUser(Long userId) {
return redisTemplate.opsForHash().entries("user:" + userId);
}
}
11.6 List 示例(简单队列)
@Service
public class QueueService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void pushOrderTask(String orderId) {
redisTemplate.opsForList().leftPush("queue:order", orderId);
}
public String popOrderTask() {
Object val = redisTemplate.opsForList().rightPop("queue:order");
return val == null ? null : val.toString();
}
}
11.7 Set / ZSet 示例(标签与排行榜)
@Service
public class RankService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void addTag(Long userId, String tag) {
redisTemplate.opsForSet().add("tags:user:" + userId, tag);
}
public void score(String game, String userId, double score) {
redisTemplate.opsForZSet().add("rank:" + game, userId, score);
}
public Set<ZSetOperations.TypedTuple<Object>> top10(String game) {
return redisTemplate.opsForZSet().reverseRangeWithScores("rank:" + game, 0, 9);
}
}
11.8 Bitmap 示例(签到)
@Service
public class SignService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public void sign(Long userId, LocalDate date) {
String key = "sign:" + date.getYear() + ":" + date.getMonthValue();
int offset = date.getDayOfMonth() - 1;
stringRedisTemplate.opsForValue().setBit(key + ":" + userId, offset, true);
}
public boolean hasSigned(Long userId, LocalDate date) {
String key = "sign:" + date.getYear() + ":" + date.getMonthValue();
int offset = date.getDayOfMonth() - 1;
Boolean bit = stringRedisTemplate.opsForValue().getBit(key + ":" + userId, offset);
return Boolean.TRUE.equals(bit);
}
}
11.9 HyperLogLog 示例(UV)
@Service
public class UvService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public void addVisit(String day, String userId) {
stringRedisTemplate.opsForHyperLogLog().add("uv:" + day, userId);
}
public long count(String day) {
Long size = stringRedisTemplate.opsForHyperLogLog().size("uv:" + day);
return size == null ? 0 : size;
}
}
11.10 Geo 示例(附近门店)
@Service
public class GeoService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public void addShop(String city, String shopId, double lon, double lat) {
stringRedisTemplate.opsForGeo().add("geo:shop:" + city, new Point(lon, lat), shopId);
}
public GeoResults<RedisGeoCommands.GeoLocation<String>> nearby(String city, double lon, double lat) {
Circle area = new Circle(new Point(lon, lat), new Distance(5, RedisGeoCommands.DistanceUnit.KILOMETERS));
return stringRedisTemplate.opsForGeo().radius(
"geo:shop:" + city,
area,
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().sortAscending().limit(20)
);
}
}
11.11 Pub/Sub 示例(实时通知)
发布者:
@Service
public class PubService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public void publish(String channel, String message) {
stringRedisTemplate.convertAndSend(channel, message);
}
}
订阅者:
@Configuration
public class RedisSubscriberConfig {
@Bean
public RedisMessageListenerContainer container(
RedisConnectionFactory factory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
container.addMessageListener(listenerAdapter, new PatternTopic("news:*"));
return container;
}
@Bean
public MessageListenerAdapter listenerAdapter(RedisSubscriber subscriber) {
return new MessageListenerAdapter(subscriber, "onMessage");
}
}
@Component
public class RedisSubscriber {
public void onMessage(String message, String pattern) {
System.out.println("channel pattern=" + pattern + ", msg=" + message);
}
}
11.12 Stream 示例(消费组)
生产消息:
@Service
public class StreamProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
public RecordId sendOrder(String orderId, String userId, String amount) {
Map<String, String> map = new HashMap<>();
map.put("orderId", orderId);
map.put("userId", userId);
map.put("amount", amount);
return stringRedisTemplate.opsForStream().add("stream:order", map);
}
}
消费消息:
@Service
public class StreamConsumer {
@Resource
private StringRedisTemplate stringRedisTemplate;
@PostConstruct
public void initGroup() {
try {
stringRedisTemplate.opsForStream().createGroup("stream:order", ReadOffset.latest(), "g1");
} catch (Exception ignored) {
// group may already exist
}
}
@Scheduled(fixedDelay = 1000)
public void consume() {
List<MapRecord<String, Object, Object>> records = stringRedisTemplate.opsForStream().read(
Consumer.from("g1", "c1"),
StreamReadOptions.empty().count(10).block(Duration.ofSeconds(1)),
StreamOffset.create("stream:order", ReadOffset.lastConsumed())
);
if (records == null || records.isEmpty()) {
return;
}
for (MapRecord<String, Object, Object> r : records) {
// TODO: 处理业务
stringRedisTemplate.opsForStream().acknowledge("stream:order", "g1", r.getId());
}
}
}
11.13 分布式锁(SET NX EX)
简版实现(单机 Redis 可用):
@Service
public class RedisLockService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public boolean tryLock(String key, String requestId, long seconds) {
Boolean ok = stringRedisTemplate.opsForValue().setIfAbsent(key, requestId, Duration.ofSeconds(seconds));
return Boolean.TRUE.equals(ok);
}
public void unlock(String key, String requestId) {
String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) else return 0 end";
stringRedisTemplate.execute(
new DefaultRedisScript<>(lua, Long.class),
Collections.singletonList(key),
requestId
);
}
}
生产建议:优先使用 Redisson
RLock,处理续期、可重入、看门狗更完善。
11.14 Spring Cache + Redis
启动类开启缓存:
@EnableCaching
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
业务方法:
@Service
public class ProductService {
@Cacheable(cacheNames = "product", key = "#id")
public Product findById(Long id) {
// 模拟查库
return new Product(id, "phone", 3999);
}
@CacheEvict(cacheNames = "product", key = "#id")
public void evict(Long id) {
}
}
缓存管理器配置(TTL):
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cfg = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(cfg).build();
}
}
11.15 防止缓存问题(穿透/击穿/雪崩)
穿透
- 空值缓存(短 TTL)
- 参数校验
- 布隆过滤器
击穿
- 热点 key 加互斥锁
- 逻辑过期 + 后台重建
雪崩
- TTL 随机抖动
- 多级缓存
- 限流降级
示例(TTL 抖动):
long base = 600;
long jitter = ThreadLocalRandom.current().nextLong(60);
redisTemplate.opsForValue().set(key, value, Duration.ofSeconds(base + jitter));
11.16 限流示例(Lua + INCR)
@Service
public class RateLimitService {
@Resource
private StringRedisTemplate stringRedisTemplate;
private static final String LUA = ""
+ "local key=KEYS[1]\n"
+ "local limit=tonumber(ARGV[1])\n"
+ "local ttl=tonumber(ARGV[2])\n"
+ "local current=redis.call('incr', key)\n"
+ "if current==1 then redis.call('expire', key, ttl) end\n"
+ "if current>limit then return 0 else return 1 end";
public boolean allow(String bizKey, int limit, int seconds) {
Long ret = stringRedisTemplate.execute(
new DefaultRedisScript<>(LUA, Long.class),
Collections.singletonList("rl:" + bizKey),
String.valueOf(limit),
String.valueOf(seconds)
);
return ret != null && ret == 1L;
}
}
11.17 幂等控制示例
public boolean checkAndMark(String requestId) {
Boolean ok = stringRedisTemplate.opsForValue()
.setIfAbsent("idem:" + requestId, "1", Duration.ofMinutes(10));
return Boolean.TRUE.equals(ok); // true: 首次请求
}
11.18 Session 共享(可选)
可使用 Spring Session + Redis 存储会话,实现多实例共享登录态。
依赖:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
11.19 Sentinel / Cluster 在 Spring Boot 中配置
Sentinel
spring:
data:
redis:
sentinel:
master: mymaster
nodes:
- 10.0.0.11:26379
- 10.0.0.12:26379
- 10.0.0.13:26379
password: 123456
Cluster
spring:
data:
redis:
cluster:
nodes:
- 10.0.0.21:6379
- 10.0.0.22:6379
- 10.0.0.23:6379
password: 123456
12. 生产实践建议
- key 规范:
业务:模块:标识,如order:detail:1001 - 避免大 value(建议 < 10KB,按业务权衡)
- 监控命中率、QPS、连接数、慢查询、内存碎片率
- 双写一致性要设计补偿机制(消息或定时修复)
- 热 key 前置本地缓存 + 限流
13. 常见问题排查
13.1 WRONGTYPE Operation against a key holding the wrong kind of value
原因:同名 key 被不同数据类型复用。
处理:统一 key 前缀和数据类型约定。
13.2 连接超时
- 检查 Redis 地址、端口、密码
- 检查连接池参数是否过小
- 检查防火墙与云安全组
13.3 内存持续增长
- 排查是否无 TTL
- 检查大 key、聚合类 key
- 检查淘汰策略是否合理
14. 一份可直接复用的 Spring Boot 实战组合
推荐组合:
- 缓存:
@Cacheable + RedisCacheManager - 计数:
INCR - 排行榜:
ZSet - 限流:
Lua - 分布式锁:
Redisson - 消息:
Stream + 消费组 - 幂等:
setIfAbsent + TTL
15. 学习路线建议
- 第 1 阶段:String/Hash/List/Set/ZSet + TTL
- 第 2 阶段:缓存实战 + 缓存三大问题
- 第 3 阶段:分布式锁 + 限流 + 幂等
- 第 4 阶段:Stream + Sentinel/Cluster + 监控治理
16. 官方文档
如果你愿意,我可以下一步继续给你补一份:
redis实战案例大全.md(秒杀、购物车、点赞系统、排行榜、签到、消息队列)- 或者直接生成一个可运行的
springboot-redis-demo项目骨架(Controller + Service + 测试用例)。