盐城做网站,网站建设维护概括总结,产品开发流程表,微信小程序制作工具平台#x1f4da; 目录#xff08;点击跳转对应章节#xff09;
一、基础线程优化#xff1a;不使用注解的手动缓存实现 1.1 传统MySQL查询性能瓶颈分析1.2 手动Redis缓存实现方式1.3 线程安全问题及解决方案 二、SpringBoot Cache线程优化注解详解 2.1 Spring Cache核心注解介… 目录点击跳转对应章节一、基础线程优化不使用注解的手动缓存实现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查询菜品)publicResultListDishVOlist(LongcategoryId){//构造redis中的key规则dish_分类idStringkeydish_categoryId;//查询redis中是否存在菜品数据ListDishVOlist(ListDishVO)redisTemplate.opsForValue().get(key);if(list!nulllist.size()0){//如果存在直接返回无须查询数据库returnResult.success(list);}DishdishnewDish();dish.setCategoryId(categoryId);dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品//如果不存在查询数据库将查询到的数据放入redis中listdishService.listWithFlavor(dish);redisTemplate.opsForValue().set(key,list);returnResult.success(list);}以上关于redis的java操作可以去看这篇文章有详细讲解https://blog.csdn.net/yyzytx5201314/article/details/155777981?spm1001.2014.3001.5502经过优化后再次进行原来的查询操作时当进行数据库查询时数据库会进行查询并返回查询结果返回结果会进行缓存下次再进行相同的查询操作时会直接从缓存中获取数据从而大大提高查询效率1.3 线程安全问题及解决方案出现的问题当mysql数据库中的数据改变时而redis中缓存的数据未得到改变就会出现数据不一致的问题因此我们要进行手动添加处理的方法这是进行的测试解决方法//在要解决缓存不一致的地方加入如上的操作AutowiredprivateRedisTemplateredisTemplate;/** * 清理缓存数据 * param pattern */privatevoidcleanCache(Stringpattern){SetkeysredisTemplate.keys(pattern);redisTemplate.delete(keys);}新增菜品优化/** * 新增菜品 * * param dishDTO * return */PostMappingOperation(summary新增菜品)publicResultsave(RequestBodyDishDTOdishDTO){log.info(新增菜品{},dishDTO);dishService.saveWithFlavor(dishDTO);//清理缓存数据Stringkeydish_dishDTO.getCategoryId();cleanCache(key);returnResult.success();}菜品批量删除优化/** * 批量删除菜品 * * param ids * return */DeleteMappingOperation(summary批量删除菜品)publicResultdelete(RequestParamListLongids){log.info(批量删除菜品{},ids);dishService.deleteBatch(ids);//清理缓存数据cleanCache(dish_*);returnResult.success();}修改菜品优化/** * 修改菜品 * * param dishDTO * return */PutMappingApiOperation(修改菜品)publicResultupdate(RequestBodyDishDTOdishDTO){log.info(修改菜品{},dishDTO);dishService.updateWithFlavor(dishDTO);//清理缓存数据cleanCache(dish_*);returnResult.success();}菜品起售停售优化/** * 菜品起售停售 * * param status * param id * return */PostMapping(/status/{status})ApiOperation(菜品起售停售)publicResultStringstartOrStop(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;Slf4jSpringBootApplicationEnableCaching//开启缓存注解功能publicclassCacheDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(CacheDemoApplication.class,args);log.info(项目启动成功...);}}Cacheable注解/** * Cacheable在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据 * 调用方法并将方法返回值放到缓存中 * value缓存的名称每个缓存名称下面可以有多个key * key缓存的key */GetMappingCacheable(cacheNamesuserCache,key#id)publicUsergetById(Longid){UseruseruserMapper.getById(id);returnuser;}key的扩展可以使用SpEL表达式来动态生成key例如key“#user.id”表示根据user对象的id属性作为keyCachePut注解/** * CachePut在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据 * 调用方法并将方法返回值放到缓存中 * value缓存的名称每个缓存名称下面可以有多个key * key缓存的key */PutMappingCachePut(cacheNamesuserCache,key#user.id)publicUserupdate(RequestBodyUseruser){userMapper.update(user);returnuser;}CacheEvict注解/** * CacheEvict在方法执行前spring先查看缓存中是否有数据如果有数据则直接返回缓存数据若没有数据 * 调用方法并将方法返回值放到缓存中 * value缓存的名称每个缓存名称下面可以有多个key * key缓存的key */DeleteMappingCacheEvict(cacheNamesuserCache,key#id)publicResultdelete(Longid){userMapper.delete(id);returnResult.success();}三、苍穹外卖项目中的实际应用案例3.1 项目中的实际使用service层的具体缓存应用场景// DishServiceImpl.java - 菜品业务层实现类节选关键缓存相关代码ServicepublicclassDishServiceImplimplementsDishService{// ... 其他代码 .../** * 新增菜品和对应的口味 * * param dishDTO */TransactionalCacheEvict(valuedishCache,key#dishDTO.categoryId)OverridepublicvoidsaveWithFlavor(DishDTOdishDTO){// ... 实现代码 ...}/** * 菜品批量删除 * * param ids */TransactionalCacheEvict(valuedishCache,allEntriestrue)OverridepublicvoiddeleteBatch(ListLongids){// ... 实现代码 ...}/** * 根据id修改菜品的基本信息和对应的口味信息 * param dishDTO */TransactionalCacheEvict(valuedishCache,allEntriestrue)OverridepublicvoidupdateWithFlavor(DishDTOdishDTO){// ... 实现代码 ...}/** * 菜品的起售和停售关联套餐进行操作 * param status * param id */OverrideCacheEvict(valuedishCache,allEntriestrue)publicvoidstartOrStop(Integerstatus,Longid){// ... 实现代码 ...}/** * 条件查询菜品和口味 * param dish * return */OverrideCacheable(valuedishCache,key#dish.categoryId)publicListDishVOlistWithFlavor(Dishdish){// ... 实现代码 ...}// ... 其他代码 ...}3.2 ai给出的额外配置优化// RedisConfiguration.java - Redis缓存配置类ConfigurationSlf4jpublicclassRedisConfiguration{// ... 其他代码 ...BeanpublicCacheManagercacheManager(RedisConnectionFactoryredisConnectionFactory){RedisCacheConfigurationcacheConfigurationRedisCacheConfiguration.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 操作。始终关注缓存一致性更新/删除操作及时清除相关缓存并合理设置过期时间。