news 2026/5/26 12:50:45

Spring Cache + Redis 缓存套餐数据,我是这样在Spring Boot项目里省掉80%数据库查询的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Cache + Redis 缓存套餐数据,我是这样在Spring Boot项目里省掉80%数据库查询的

Spring Cache + Redis 实战:如何用缓存套餐数据减少80%数据库查询

在电商和外卖系统中,套餐数据往往是高频查询但低频变更的典型场景。想象一下,每当用户浏览餐厅页面时,系统都要反复查询数据库获取相同的套餐信息,这种设计不仅浪费资源,还会在流量高峰时成为性能瓶颈。本文将分享一套经过实战验证的Spring Cache与Redis整合方案,通过简单的注解配置,让你的系统轻松应对高并发查询。

1. 环境准备与基础配置

1.1 依赖引入与Redis连接

首先确保项目中包含必要的依赖项。在Maven项目中,除了标准的Spring Boot Starter依赖外,需要特别添加这两个关键依赖:

<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>

Redis配置通常放在application.yml中,以下是一个生产级配置示例:

spring: redis: host: your-redis-host port: 6379 password: your-password-if-any lettuce: pool: max-active: 20 max-idle: 10 min-idle: 5 max-wait: 3000ms

1.2 启用缓存功能

在Spring Boot启动类上添加@EnableCaching注解是激活缓存功能的钥匙:

@SpringBootApplication @EnableCaching public class FoodDeliveryApplication { public static void main(String[] args) { SpringApplication.run(FoodDeliveryApplication.class, args); } }

2. 核心缓存注解实战应用

2.1 @Cacheable:查询缓存化

这个注解是减少数据库查询的主力军。以下是一个套餐查询的典型应用:

@GetMapping("/meals/{id}") @Cacheable(value = "mealCache", key = "#id", unless = "#result == null") public Meal getMealById(@PathVariable Long id) { log.info("查询数据库获取套餐ID: {}", id); return mealRepository.findById(id).orElse(null); }

关键参数说明:

  • value:定义缓存名称,相当于命名空间
  • key:缓存键的生成规则,支持SpEL表达式
  • unless:条件过滤,这里表示结果为null时不缓存

2.2 @CachePut:更新缓存策略

当套餐数据变更时,我们需要同步更新缓存:

@PostMapping("/meals") @CachePut(value = "mealCache", key = "#meal.id") public Meal createMeal(@RequestBody Meal meal) { return mealRepository.save(meal); }

2.3 @CacheEvict:缓存失效处理

删除或禁用套餐时,需要清理对应的缓存:

@DeleteMapping("/meals/{id}") @CacheEvict(value = "mealCache", key = "#id") public void deleteMeal(@PathVariable Long id) { mealRepository.deleteById(id); }

对于批量操作,可以使用:

@CacheEvict(value = "mealCache", allEntries = true) public void refreshAllMeals() { // 批量更新逻辑 }

3. 高级缓存策略与优化

3.1 缓存穿透防护

当查询不存在的套餐ID时,可能会引发缓存穿透。解决方案是缓存空结果:

@Cacheable(value = "mealCache", key = "#id", unless = "#result == null") public Meal getMealWithNullCache(Long id) { Meal meal = mealRepository.findById(id).orElse(null); if(meal == null) { // 记录不存在的键,用于监控 log.warn("不存在的套餐查询: {}", id); } return meal; }

3.2 缓存雪崩预防

为不同的缓存项设置随机的TTL可以避免同时失效:

@Configuration public class RedisConfig { @Bean public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() { return builder -> builder .withCacheConfiguration("mealCache", RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(30 + new Random().nextInt(15)))); } }

3.3 本地缓存二级加速

对于极端热点的套餐数据,可以引入Caffeine作为本地二级缓存:

@Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new CaffeineRedisCacheManager( Caffeine.newBuilder() .expireAfterWrite(5, TimeUnit.MINUTES) .maximumSize(1000), RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(1)) ); }

4. 监控与问题排查

4.1 缓存命中率监控

通过自定义CacheInterceptor可以统计命中率:

public class MetricsCacheInterceptor extends CacheInterceptor { private final MeterRegistry meterRegistry; @Override protected Object doGet(Cache cache, Object key, Method method) { Object value = super.doGet(cache, key, method); String cacheName = cache.getName(); meterRegistry.counter("cache.gets", "cache", cacheName, "hit", value != null ? "true" : "false").increment(); return value; } }

4.2 常见问题排查表

问题现象可能原因解决方案
缓存未生效注解未正确应用或方法被内部调用确保方法为public且通过代理调用
数据不一致缓存更新延迟或失败检查@CachePut/@CacheEvict逻辑
Redis连接超时网络问题或连接池不足调整连接池参数,增加超时设置
内存占用高缓存无过期或缓存过多无用数据设置合理的TTL和淘汰策略

4.3 缓存预热策略

系统启动时自动加载热点数据:

@EventListener(ApplicationReadyEvent.class) public void warmUpCache() { List<Long> hotMealIds = mealRepository.findTop100ByOrderBySalesDesc() .stream().map(Meal::getId).collect(Collectors.toList()); hotMealIds.parallelStream().forEach(id -> { mealService.getMealById(id); }); }

5. 性能对比与实战建议

在实际的外卖系统中,我们对套餐查询接口进行了压力测试:

测试环境:

  • 4核8G服务器
  • Redis 6.2集群
  • 1000个模拟套餐数据

测试结果:

场景QPS平均响应时间数据库负载
无缓存12085ms100%
仅Redis350028ms5%
Redis+本地缓存580012ms2%

实战建议:

  1. 对于套餐这类读多写少的数据,TTL建议设置在30-60分钟
  2. 关键业务操作(如订单创建)完成后,立即刷新相关缓存
  3. 使用@CacheConfig在类级别统一配置公共缓存属性
  4. 定期分析缓存命中率,淘汰低效缓存

在最近的一个外卖平台优化项目中,这套方案将套餐查询的数据库访问量降低了82%,API响应时间从平均76ms降至9ms。特别是在午晚高峰时段,系统稳定性得到显著提升。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 11:17:34

解锁AMD Ryzen隐藏性能:SMUDebugTool完全实战指南

解锁AMD Ryzen隐藏性能&#xff1a;SMUDebugTool完全实战指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/5/22 11:16:49

2026 论文降重降 AIGC 十大工具横评:从查重到消痕一站式通关

毕业季论文修改&#xff0c;查重飘红、AI 痕迹超标已成为本科生与硕博生的两大 “拦路虎”。随着知网、维普、格子达等平台 AIGC 检测算法持续升级&#xff0c;单一降重工具已难以兼顾重复率与 AI 率双达标。本文横向测评 2026 年十大主流论文查重与降重 / AIGC 工具&#xff0…

作者头像 李华
网站建设 2026/5/22 11:15:07

你的私人游戏服务器:Sunshine如何重新定义跨设备游戏体验

你的私人游戏服务器&#xff1a;Sunshine如何重新定义跨设备游戏体验 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 想象一下这样的场景&#xff1a;你在书房的高性能游戏PC上刚刚…

作者头像 李华
网站建设 2026/5/22 11:01:05

如何在Windows系统上完整启用MacBook Pro Touch Bar显示功能

如何在Windows系统上完整启用MacBook Pro Touch Bar显示功能 【免费下载链接】DFRDisplayKm Windows infrastructure support for Apple DFR (Touch Bar) 项目地址: https://gitcode.com/gh_mirrors/df/DFRDisplayKm 还在为MacBook Pro在Windows系统中Touch Bar只能用作…

作者头像 李华
网站建设 2026/5/22 10:55:18

ARM AArch32虚拟内存系统架构与优化实践

1. AArch32虚拟内存系统架构概述 虚拟内存是现代计算机系统的核心机制&#xff0c;它通过地址转换技术将程序使用的虚拟地址&#xff08;VA&#xff09;映射到物理内存的实际位置&#xff08;PA&#xff09;。ARM架构中的AArch32虚拟内存系统架构&#xff08;VMSAv8-32&#xf…

作者头像 李华