1. 基本概念
RedisCache
- 定位:自定义封装的Redis缓存工具类
- 特点:通常针对业务场景进行了高层抽象
- 典型功能:
- 带过期时间的缓存操作
- 自定义序列化方式
- 业务键前缀管理
- 简化常用操作API
StringRedisTemplate
- 定位:Spring官方提供的Redis操作模板
- 特点:专注于字符串操作的基础工具
- 核心特性:
- 直接继承自RedisTemplate
- 默认使用String序列化器
- 提供完整的Redis命令支持
2. 核心差异对比
特性 | RedisCache | StringRedisTemplate |
---|---|---|
抽象层级 | 高层业务抽象 | 底层命令封装 |
序列化方式 | 可自定义(通常JSON/Java序列化) | 固定String序列化 |
使用场景 | 业务缓存操作 | 原始Redis命令操作 |
开发效率 | 高(简化API) | 低(需手动处理更多细节) |
灵活性 | 较低(受封装限制) | 极高(可执行任意Redis命令) |
学习成本 | 低(业务语义明确) | 中(需了解Redis命令) |
典型方法 | setCacheObject/getCacheObject | opsForValue/opsForHash等 |
3. 代码实现对比
RedisCache典型实现
// 设置带过期时间的缓存
redisCache.setCacheObject("user:1001", user, 10, TimeUnit.MINUTES);
// 获取对象
User cachedUser = redisCache.getCacheObject("user:1001");
// 删除键
redisCache.deleteObject("user:1001");
StringRedisTemplate典型实现
// 设置字符串值
stringRedisTemplate.opsForValue().set("user:1001", "{\"name\":\"张三\"}");
// 设置过期时间
stringRedisTemplate.expire("user:1001", 10, TimeUnit.MINUTES);
// 获取值
String userJson = stringRedisTemplate.opsForValue().get("user:1001");
// 转换为对象
User user = JSON.parseObject(userJson, User.class);
4. 序列化差异详解
RedisCache序列化
// 典型配置方式(使用Jackson序列化)
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(User.class));
StringRedisTemplate序列化
// 固定使用String序列化器
public class StringRedisTemplate extends RedisTemplate<String, String> {
public StringRedisTemplate() {
setKeySerializer(RedisSerializer.string());
setValueSerializer(RedisSerializer.string());
// ...其他配置
}
}
5. 性能考量
序列化开销:
- RedisCache可能使用JSON/Java序列化,开销较大
- StringRedisTemplate仅处理字符串,效率最高
网络IO:
- RedisCache可能因封装增加少量开销
- StringRedisTemplate更接近原生Redis协议
内存占用:
- JSON序列化通常比Java序列化体积小
- 纯字符串操作内存效率最高
6. 最佳实践建议
使用RedisCache当:
- 需要快速开发业务缓存功能
- 处理复杂对象存储
- 需要统一的缓存管理策略
- 项目已集成该工具类
使用StringRedisTemplate当:
- 需要直接操作Redis原生命令
- 处理简单字符串数据
- 需要极致性能优化
- 实现特殊数据结构操作
7. 混合使用模式
@Service
public class UserService {
@Autowired
private RedisCache redisCache; // 用于对象缓存
@Autowired
private StringRedisTemplate stringRedisTemplate; // 用于特殊操作
public void updateUser(User user) {
// 使用RedisCache缓存对象
redisCache.setCacheObject("user:"+user.getId(), user);
// 使用StringRedisTemplate维护ID索引
stringRedisTemplate.opsForSet().add("user:ids", user.getId().toString());
}
}
8. 扩展比较:与RedisTemplate的关系
特性 | RedisCache | StringRedisTemplate | RedisTemplate |
---|---|---|---|
序列化 | 自定义 | String | 可配置 |
使用复杂度 | 简单 | 中等 | 复杂 |
适用数据 | 业务对象 | 字符串 | 任意类型 |
性能 | 中等 | 高 | 取决于配置 |
9. 实战选择建议
新项目开发:
- 优先使用RedisCache规范缓存使用
- 在特殊场景辅以StringRedisTemplate
遗留系统维护:
- 保持原有方式
- 逐步将StringRedisTemplate迁移到RedisCache
性能关键路径:
- 考虑直接使用StringRedisTemplate
- 或优化RedisCache的序列化方式
团队规范:
- 统一缓存工具使用方式
- 明确两种组件的使用边界
10. 常见问题解决方案
问题1:如何用StringRedisTemplate存储对象?
// 序列化为JSON存储
String userJson = JSON.toJSONString(user);
stringRedisTemplate.opsForValue().set(key, userJson);
// 读取时反序列化
User user = JSON.parseObject(stringRedisTemplate.opsForValue().get(key), User.class);
问题2:RedisCache如何实现原子操作?
// 借助StringRedisTemplate实现
Boolean locked = stringRedisTemplate.opsForValue()
.setIfAbsent("lock:order", "1", 10, TimeUnit.SECONDS);
问题3:如何统一两者的键前缀?
// 自定义Key生成器
public class CacheKeyHelper {
public static String bizKey(String prefix, Object id) {
return prefix + ":" + id;
}
}
// 统一使用
String key = CacheKeyHelper.bizKey("user", 1001);