SpringBoot + Redis 缓存实战

1、业务场景

本智慧社区 Redis 两处核心业务:

  1. 登录验证码:GET /captcha,存入 redis,2 分钟过期;登录校验完成删除 key;
  2. 动态路由接口/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、缓存设计踩坑总结
  1. 序列化乱码必须自定义 RedisTemplate,不要直接使用默认;
  2. key 命名规范:业务:模块:id,例如router:user:1、captcha:uuid;
  3. 必须设置 TTL 过期,防止 redis 内存无限膨胀;
  4. 更新数据库之后主动删除缓存,不要更新缓存(旁路缓存最佳实践);
  5. 热点数据缓存,不要缓存频繁变更数据;
  6. 防止缓存穿透:数据库不存在数据,也要缓存空值,设置短 TTL。
相关推荐
真恋寄语枫秋42 分钟前
【Java零基础入门28】Java包机制详解:package包定义、import导入、权限访问、项目分层管理
java
西柚不烦恼44 分钟前
jenkins版本和java版本的依赖
java·开发语言·jenkins
牧瀬クリスだ1 小时前
Ajax入门:从原生XHR到axios实战
java·spring boot·ajax·okhttp
IT_陈寒1 小时前
深入理解Redis:核心原理与最佳实践
前端·人工智能·后端
来福猿1 小时前
分布式锁 Redis 实现源码分析:SETNX、过期时间与可重入设计
数据库·redis·分布式
打工仔折腾 AI1 小时前
鸿蒙端ToDesk远控电脑实测:蓝牙键鼠、双模式鼠标与跨端剪贴板实践
后端·python·性能优化·计算机外设·电脑·harmonyos·ai agent 实战
AINative软件工程1 小时前
LLM 异步任务的 Webhook 工程实践:回调可靠投递、重试与幂等消费的生产设计
后端·ai编程
豆角焖肉1 小时前
SpringBoot+JWT 实现前后端分离登录鉴权
java·开发语言·spring boot·jwt·前后端分离·登录认证
高频因子挖掘机1 小时前
Python 批量获取股票行情后,如何用 Pandas 统一字段、索引和数据类型?
后端·github·api