Skip to main content

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 淘汰策略(内存满时)

常见:

  • noeviction
  • allkeys-lru
  • allkeys-lfu
  • volatile-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 + 测试用例)。