1、业务场景
本智慧社区 Redis 两处核心业务:
- 登录验证码:GET
/captcha,存入 redis,2 分钟过期;登录校验完成删除 key; - 动态路由接口
/sys/user/getRouters:登录之后获取用户信息 + 路由菜单,这个接口访问频率高,数据库查询角色、菜单树,缓存到 redis,减少 mysql 查询。
用户修改角色 / 修改菜单之后,需要主动删除对应缓存 key,保证下次读取最新数据。
2、pom 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‑boot‑starter‑data‑redis</artifactId>
</dependency>
application.yml 配置 redis 连接,timeout,连接池。
3、RedisTemplate 配置类(重点解决序列化乱码)
默认 JDK 序列化,key 和 value 出现 \xAC\xED 乱码;改用 Jackson2JsonRedisSerializer。
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//设置key序列化
StringRedisSerializer keySerializer = new StringRedisSerializer();
template.setKeySerializer(keySerializer);
template.setHashKeySerializer(keySerializer);
//value JSON序列化
Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jsonSerializer.setObjectMapper(mapper);
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
4、验证码业务(前面博客 captcha 接口已经用到)
//存储验证码,key=captcha:{uuid},value验证码,2分钟过期
redisTemplate.opsForValue().set("captcha:"+uuid,code,2,TimeUnit.MINUTES);
//登录成功删除验证码
redisTemplate.delete("captcha:"+uuid);
5、动态路由菜单缓存业务 getRouters
public Result getRouters(Long userId){
String cacheKey = "router:user:"+userId;
//1.先查缓存
Object cacheObj = redisTemplate.opsForValue().get(cacheKey);
if(cacheObj != null){
return Result.success(cacheObj);
}
//2.缓存未命中,查询数据库:用户信息,角色,菜单树组装routers
RouterVO vo = buildRouterByDb(userId);
//3.写入缓存,设置过期时间
redisTemplate.opsForValue().set(cacheKey,vo,1,TimeUnit.HOURS);
return Result.success(vo);
}
缓存失效策略:当修改角色、修改菜单接口执行完成,执行删除缓存 key。
//修改角色完成之后清除该用户路由缓存
redisTemplate.delete("router:user:"+userId);
6、缓存设计踩坑总结
- 序列化乱码必须自定义 RedisTemplate,不要直接使用默认;
- key 命名规范:业务:模块:id,例如
router:user:1、captcha:uuid; - 必须设置 TTL 过期,防止 redis 内存无限膨胀;
- 更新数据库之后主动删除缓存,不要更新缓存(旁路缓存最佳实践);
- 热点数据缓存,不要缓存频繁变更数据;
- 防止缓存穿透:数据库不存在数据,也要缓存空值,设置短 TTL。