目录
一、为什么选择 Redis?
在现代应用开发中,Redis 已成为高性能缓存和分布式数据存储的首选方案。作为内存数据结构存储系统,Redis 提供:
- 亚毫秒级响应速度(10万+ QPS)
- 丰富的数据结构支持
- 持久化选项(RDB/AOF)
- 高可用架构(主从复制、哨兵、集群)
Spring Boot 通过 Spring Data Redis 模块提供了与 Redis 的无缝集成,极大简化了开发流程。
二、Spring Boot 整合 Redis 步骤
1. 添加依赖
在 pom.xml
中添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId> <!-- 推荐使用 Jedis 客户端 -->
</dependency>
2. 配置 Redis 连接
在 application.yml
中配置:
spring:
redis:
host: localhost
port: 6379
password: your-password # 如果有密码
database: 0 # 默认数据库索引
jedis:
pool:
max-active: 8 # 连接池最大连接数
max-idle: 8 # 连接池最大空闲连接
min-idle: 2 # 连接池最小空闲连接
3. 配置 RedisTemplate
创建配置类:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用Jackson序列化器
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(
om.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.NON_FINAL
);
serializer.setObjectMapper(om);
// 设置序列化
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
三、Redis 五大核心数据类型
1. String(字符串)
特点:最基本的数据类型,最大能存储 512MB
常用场景:
- 缓存简单值
- 计数器
- 分布式锁
操作示例:
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 设置值
redisTemplate.opsForValue().set("user:1001:name", "Alice");
// 获取值
String name = (String) redisTemplate.opsForValue().get("user:1001:name");
// 自增计数器
redisTemplate.opsForValue().increment("article:1001:views");
// 设置带过期时间(30分钟)
redisTemplate.opsForValue().set("temp:session", "data", 30, TimeUnit.MINUTES);
2. Hash(哈希)
特点:键值对集合,适合存储对象
常用场景:
- 存储用户资料
- 商品属性
- 配置信息
操作示例:
// 存储用户对象
Map<String, String> userMap = new HashMap<>();
userMap.put("name", "Bob");
userMap.put("age", "30");
userMap.put("email", "bob@example.com");
redisTemplate.opsForHash().putAll("user:1002", userMap);
// 获取单个字段
String email = (String) redisTemplate.opsForHash().get("user:1002", "email");
// 更新单个字段
redisTemplate.opsForHash().put("user:1002", "age", "31");
// 获取所有字段
Map<Object, Object> userData = redisTemplate.opsForHash().entries("user:1002");
3. List(列表)
特点:有序、可重复的字符串集合
常用场景:
- 消息队列
- 最新消息排行
- 记录日志
操作示例:
// 从左侧插入
redisTemplate.opsForList().leftPush("news:latest", "Article 1");
redisTemplate.opsForList().leftPush("news:latest", "Article 2");
// 从右侧插入
redisTemplate.opsForList().rightPush("news:latest", "Article 3");
// 获取范围数据(0到10)
List<Object> latestNews = redisTemplate.opsForList().range("news:latest", 0, 10);
// 列表长度
Long size = redisTemplate.opsForList().size("news:latest");
// 模拟队列消费
Object article = redisTemplate.opsForList().rightPop("news:queue", 10, TimeUnit.SECONDS);
4. Set(集合)
特点:无序、不可重复的元素集合
常用场景:
- 标签系统
- 共同好友
- 唯一访客统计
操作示例:
// 添加元素
redisTemplate.opsForSet().add("article:1001:tags", "tech", "java", "spring");
// 获取所有元素
Set<Object> tags = redisTemplate.opsForSet().members("article:1001:tags");
// 检查元素是否存在
boolean containsJava = redisTemplate.opsForSet().isMember("article:1001:tags", "java");
// 集合运算(交集)
Set<Object> commonTags = redisTemplate.opsForSet().intersect(
"article:1001:tags",
"article:1002:tags"
);
// 唯一访客统计
redisTemplate.opsForSet().add("article:1001:visitors", "192.168.1.1");
Long visitors = redisTemplate.opsForSet().size("article:1001:visitors");
5. Sorted Set(有序集合)
特点:带分数排序的Set
常用场景:
- 排行榜
- 带权重的队列
- 范围查询
操作示例:
// 添加带分数的元素
redisTemplate.opsForZSet().add("leaderboard", "player1", 2500);
redisTemplate.opsForZSet().add("leaderboard", "player2", 1800);
redisTemplate.opsForZSet().add("leaderboard", "player3", 3000);
// 获取前3名玩家
Set<ZSetOperations.TypedTuple<Object>> topPlayers =
redisTemplate.opsForZSet().reverseRangeWithScores("leaderboard", 0, 2);
// 更新分数
redisTemplate.opsForZSet().incrementScore("leaderboard", "player1", 100);
// 获取玩家排名(从高到低)
Long rank = redisTemplate.opsForZSet().reverseRank("leaderboard", "player2");
// 获取分数段玩家(2000-3000分)
Set<Object> players = redisTemplate.opsForZSet().rangeByScore("leaderboard", 2000, 3000);
四、高级功能实战
1. 分布式锁实现
public boolean tryLock(String lockKey, String requestId, long expireTime) {
return Boolean.TRUE.equals(redisTemplate.execute((RedisCallback<Boolean>) connection -> {
// 使用SET命令的NX(不存在才设置)和PX(毫秒过期)选项
String result = connection.set(
lockKey.getBytes(),
requestId.getBytes(),
Expiration.milliseconds(expireTime),
RedisStringCommands.SetOption.SET_IF_ABSENT
);
return "OK".equals(result);
}));
}
public boolean releaseLock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
return Boolean.TRUE.equals(redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(lockKey),
requestId
));
}
2. 缓存注解使用
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
// 数据库查询逻辑
return userRepository.findById(id).orElse(null);
}
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
// 更新数据库
return userRepository.save(user);
}
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
3. 发布/订阅模式
// 配置消息监听容器
@Bean
public RedisMessageListenerContainer container(
RedisConnectionFactory factory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
container.addMessageListener(listenerAdapter, new PatternTopic("news.*"));
return container;
}
// 消息处理器
@Component
public class RedisMessageListener {
@Autowired
private SimpMessagingTemplate messagingTemplate;
public void handleMessage(String message, String channel) {
// 处理消息并转发到WebSocket
messagingTemplate.convertAndSend("/topic/" + channel, message);
}
}
// 发布消息
public void publish(String channel, String message) {
redisTemplate.convertAndSend(channel, message);
}
五、最佳实践与注意事项
-
键命名规范
- 使用冒号分隔层级:
业务:类型:ID
- 示例:
user:session:1001
,product:info:2005
- 使用冒号分隔层级:
-
内存优化
- 控制单个Value大小(<100KB)
- 使用Hash压缩存储小对象
- 设置合理的TTL
-
性能调优
spring: redis: jedis: pool: max-active: 50 # 根据负载调整 max-wait: 200ms
-
高可用方案
- 开发环境:单节点
- 生产环境:Redis Sentinel 或 Cluster
-
监控指标
// 获取Redis指标
@Autowired
private RedisConnectionFactory factory;
public void monitor() {
RedisConnection connection = factory.getConnection();
Properties info = connection.info();
System.out.println("内存使用: " + info.getProperty("used_memory_human"));
System.out.println("连接数: " + info.getProperty("connected_clients"));
}
六、总结
Spring Boot 与 Redis 的结合为开发者提供了强大的数据缓存和处理能力。通过掌握:
- 五大核心数据类型的适用场景和操作方法
- RedisTemplate 的高级用法
- 分布式锁、发布订阅等高级功能
- 生产环境最佳实践