news 2026/6/15 13:45:09

SpringBoot中通过SpringCache线程优化(用Redis优化MySQL)(基于苍穹外卖项目)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot中通过SpringCache线程优化(用Redis优化MySQL)(基于苍穹外卖项目)

📚 目录(点击跳转对应章节)

  • 一、基础线程优化:不使用注解的手动缓存实现
    • 1.1 传统MySQL查询性能瓶颈分析
    • 1.2 手动Redis缓存实现方式
    • 1.3 线程安全问题及解决方案
  • 二、SpringBoot Cache线程优化注解详解
    • 2.1 Spring Cache核心注解介绍
    • 2.2 Spring Cache注解使用
  • 三、苍穹外卖项目中的实际应用案例
    • 3.1 项目中的实际使用
    • 3.2 ai给出的额外配置优化
    • 3.3 注意事项
  • 四、总结

一、基础线程优化:不使用注解的手动缓存实现

1.1 传统MySQL查询性能瓶颈分析

1.1.1直接数据库访问的性能问题

  • 数据库查询性能问题

以下是苍穹外卖小程序端进行菜品套餐类查询时访问数据库的操作情景

  • 缓存引入的必要性

以上的数据库操作还只是单人进行数据库查询的情况,当数据库访问量增大时,数据库查询性能问题就会成为问题,而缓存引入则是为了解决这个问题。

1.2 手动Redis缓存实现方式

  • 缓存查询逻辑手动编码
@AutowiredprivateRedisTemplateredisTemplate;/** * 根据分类id查询菜品 * * @param categoryId * @return */@GetMapping("/list")@ApiOperation("根据分类id查询菜品")publicResult<List<DishVO>>list(LongcategoryId){//构造redis中的key,规则:dish_分类idStringkey="dish_"+categoryId;//查询redis中是否存在菜品数据List<DishVO>list=(List<DishVO>)redisTemplate.opsForValue().get(key);if(list!=null&&list.size()>0){//如果存在,直接返回,无须查询数据库returnResult.success(list);}Dishdish=newDish();dish.setCategoryId(categoryId);dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品//如果不存在,查询数据库,将查询到的数据放入redis中list=dishService.listWithFlavor(dish);redisTemplate.opsForValue().set(key,list);returnResult.success(list);}

以上关于redis的java操作可以去看这篇文章,有详细讲解https://blog.csdn.net/yyzytx5201314/article/details/155777981?spm=1001.2014.3001.5502

经过优化后再次进行原来的查询操作时

当进行数据库查询时,数据库会进行查询,并返回查询结果,返回结果会进行缓存,下次再进行相同的查询操作时,会直接从缓存中获取数据,从而大大提高查询效率

1.3 线程安全问题及解决方案

  • 出现的问题

当mysql数据库中的数据改变时,而redis中缓存的数据未得到改变就会出现数据不一致的问题,因此我们要进行手动添加处理的方法

(这是进行的测试)

  • 解决方法
//在要解决缓存不一致的地方加入如上的操作@AutowiredprivateRedisTemplateredisTemplate;/** * 清理缓存数据 * @param pattern */privatevoidcleanCache(Stringpattern){Setkeys=redisTemplate.keys(pattern);redisTemplate.delete(keys);}
  • 新增菜品优化
/** * 新增菜品 * * @param dishDTO * @return */@PostMapping@Operation(summary="新增菜品")publicResultsave(@RequestBodyDishDTOdishDTO){log.info("新增菜品:{}",dishDTO);dishService.saveWithFlavor(dishDTO);//清理缓存数据Stringkey="dish_"+dishDTO.getCategoryId();cleanCache(key);returnResult.success();}
  • 菜品批量删除优化
/** * 批量删除菜品 * * @param ids * @return */@DeleteMapping@Operation(summary="批量删除菜品")publicResultdelete(@RequestParamList<Long>ids){log.info("批量删除菜品:{}",ids);dishService.deleteBatch(ids);//清理缓存数据cleanCache("dish_*");returnResult.success();}
  • 修改菜品优化
/** * 修改菜品 * * @param dishDTO * @return */@PutMapping@ApiOperation("修改菜品")publicResultupdate(@RequestBodyDishDTOdishDTO){log.info("修改菜品:{}",dishDTO);dishService.updateWithFlavor(dishDTO);//清理缓存数据cleanCache("dish_*");returnResult.success();}
  • 菜品起售停售优化
/** * 菜品起售停售 * * @param status * @param id * @return */@PostMapping("/status/{status}")@ApiOperation("菜品起售停售")publicResult<String>startOrStop(@PathVariableIntegerstatus,Longid){dishService.startOrStop(status,id);//清理缓存数据cleanCache("dish_*");returnResult.success();}

二、SpringBoot Cache线程优化注解详解

2.1 Spring Cache核心注解介绍

  • @Cacheable:缓存查询结果
  • @CachePut:更新缓存
  • @CacheEvict:清除缓存
  • @Caching:组合多个缓存操作

2.2 Spring Cache注解使用

  • 在启动类中添加@EnableCaching注解(开启缓存注解功能)
packagecom.itheima;importlombok.extern.slf4j.Slf4j;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.cache.annotation.EnableCaching;@Slf4j@SpringBootApplication@EnableCaching//开启缓存注解功能publicclassCacheDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(CacheDemoApplication.class,args);log.info("项目启动成功...");}}
  • Cacheable注解
/** * Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据, * 调用方法并将方法返回值放到缓存中 * value:缓存的名称,每个缓存名称下面可以有多个key * key:缓存的key */@GetMapping@Cacheable(cacheNames="userCache",key="#id")publicUsergetById(Longid){Useruser=userMapper.getById(id);returnuser;}

key的扩展:可以使用SpEL表达式来动态生成key,例如:key=“#user.id”,表示根据user对象的id属性作为key

  • CachePut注解
/** * CachePut:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据, * 调用方法并将方法返回值放到缓存中 * value:缓存的名称,每个缓存名称下面可以有多个key * key:缓存的key */@PutMapping@CachePut(cacheNames="userCache",key="#user.id")publicUserupdate(@RequestBodyUseruser){userMapper.update(user);returnuser;}
  • CacheEvict注解
/** * CacheEvict:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据, * 调用方法并将方法返回值放到缓存中 * value:缓存的名称,每个缓存名称下面可以有多个key * key:缓存的key */@DeleteMapping@CacheEvict(cacheNames="userCache",key="#id")publicResultdelete(Longid){userMapper.delete(id);returnResult.success();}

三、苍穹外卖项目中的实际应用案例

3.1 项目中的实际使用

  • service层的具体缓存应用场景
// DishServiceImpl.java - 菜品业务层实现类(节选关键缓存相关代码)@ServicepublicclassDishServiceImplimplementsDishService{// ... 其他代码 .../** * 新增菜品和对应的口味 * * @param dishDTO */@Transactional@CacheEvict(value="dishCache",key="#dishDTO.categoryId")@OverridepublicvoidsaveWithFlavor(DishDTOdishDTO){// ... 实现代码 ...}/** * 菜品批量删除 * * @param ids */@Transactional@CacheEvict(value="dishCache",allEntries=true)@OverridepublicvoiddeleteBatch(List<Long>ids){// ... 实现代码 ...}/** * 根据id修改菜品的基本信息和对应的口味信息 * @param dishDTO */@Transactional@CacheEvict(value="dishCache",allEntries=true)@OverridepublicvoidupdateWithFlavor(DishDTOdishDTO){// ... 实现代码 ...}/** * 菜品的起售和停售(关联套餐进行操作) * @param status * @param id */@Override@CacheEvict(value="dishCache",allEntries=true)publicvoidstartOrStop(Integerstatus,Longid){// ... 实现代码 ...}/** * 条件查询菜品和口味 * @param dish * @return */@Override@Cacheable(value="dishCache",key="#dish.categoryId")publicList<DishVO>listWithFlavor(Dishdish){// ... 实现代码 ...}// ... 其他代码 ...}

3.2 ai给出的额外配置优化

// RedisConfiguration.java - Redis缓存配置类@Configuration@Slf4jpublicclassRedisConfiguration{// ... 其他代码 ...@BeanpublicCacheManagercacheManager(RedisConnectionFactoryredisConnectionFactory){RedisCacheConfigurationcacheConfiguration=RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1))// 设置缓存过期时间为1小时.disableCachingNullValues();// 不缓存空值returnRedisCacheManager.builder(redisConnectionFactory).cacheDefaults(cacheConfiguration).build();}}

3.3 注意事项

推荐将缓存操作加在到service层而不是controller层(黑马的课中写在了controller层,但是w 我经过查询发现service层更合适),这样service层与dao层之间的数据交互更清晰,controller层只负责接收请求与返回响应,使每个层职责更单一,更清晰,更易维护。
也更符合单一职责原则。

四、总结

在苍穹外卖项目中,通过引入 Redis 缓存显著优化了高频菜品查询的性能:从手动编码的“先查缓存、后查数据库、更新时主动清理”模式,到更优雅的 Spring Cache 注解方式(@Cacheable + @CacheEvict),有效解决了数据库压力大和缓存一致性问题。

核心收益:

  • 查询效率大幅提升。
  • 数据库负载降低,系统并发能力增强。
  • 代码更简洁、可维护性更强(推荐 Service 层使用注解)。

最佳实践建议:

  • 优先使用 Spring Cache 注解实现声明式缓存。
  • 对于精细化控制场景,可结合手动 Redis 操作。
  • 始终关注缓存一致性:更新/删除操作及时清除相关缓存,并合理设置过期时间。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 11:32:56

刷题日记day7(构造+打表)

题目描述 牛客小白月赛125F 琪露诺的排列构造题解来自大神Kendieer大神的视频讲解 思路分析 通过打表找规律 ac代码 #include<iostream>using namespace std;const int N1e510; int T;int main(){cin>>T;while(T--){int n;cin>>n;if(n<2) cout<…

作者头像 李华
网站建设 2026/6/14 13:31:34

组织结构图导出PDF 高清无水印在线生成

良功绘图网站 (https://www.lghuitu.com) 在现代组织管理中&#xff0c;组织结构图是不可或缺的核心工具。无论是企业集团的层级梳理、学校机构的职能划分、医院科室的架构呈现&#xff0c;还是街道社区的网格化管理&#xff0c;一份清晰、专业的组织结构图都能直观展现组织内…

作者头像 李华
网站建设 2026/6/13 20:04:49

协会组织架构图绘制 会员管理体系可视化

良功绘图网站 (https://www.lghuitu.com ) 在社会组织蓬勃发展的当下&#xff0c;协会作为连接行业、企业、个人的重要桥梁&#xff0c;其内部管理效率与对外服务质量直接影响着自身的凝聚力与影响力。协会的核心管理场景中&#xff0c;组织架构的清晰化与会员管理的高效化是两…

作者头像 李华
网站建设 2026/6/15 12:36:37

14、系统管理设置全解析

系统管理设置全解析 在使用系统的过程中,合理的管理设置能够提升系统的性能、安全性和使用体验。下面将为大家详细介绍一些重要的系统管理设置选项。 1. Akonadi 配置 在 KDE 环境里,Akonadi 是 Kontact 个人信息管理(PIM)应用背后的存储架构。PIM 应用可用于管理日历、…

作者头像 李华
网站建设 2026/6/11 1:07:59

3D医学影像分割实战:5步快速掌握深度学习预训练模型

3D医学影像分割实战&#xff1a;5步快速掌握深度学习预训练模型 【免费下载链接】tutorials 项目地址: https://gitcode.com/gh_mirrors/tutorial/tutorials 为什么你需要这篇指南&#xff1f; 在医学影像分析领域&#xff0c;获取高质量的标注数据往往是最头疼的问题…

作者头像 李华