苍穹外卖【day7|缓存套餐_Spring Cache】

苍穹外卖【day7|缓存套餐_Spring Cache】 个人主页:一条泥憨鱼(欢迎各位大佬莅临)精选专栏:数据结构与算法Java ,AI与AgentSpring CacheSpring Cache常用注解代码开发实现思路一、整体架构概览套餐缓存模块采用Spring Cache 注解驱动方式结合 Redis 作为缓存后端实现。┌──────────────────────────────────────────────────────────────┐ │ Spring Cache 架构 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────┐ ┌──────────────────────────┐ │ │ │ C端查询接口 │ │ Admin管理接口 │ │ │ │ Cacheable │ │ CacheEvict │ │ │ └────────┬─────────┘ └────────────┬─────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Spring Cache 抽象层 │ │ │ │ (CacheManager CacheResolver) │ │ │ └─────────────────────┬───────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Redis 缓存层 │ │ │ │ Key: setmealCache::categoryId │ │ │ │ Value: ListSetmeal │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ MySQL 数据库 │ │ │ │ setmeal 表 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘二、核心组件解析1. 缓存开启配置文件:/sky/SkyApplicationSpringBootApplication EnableTransactionManagement EnableCaching // 关键开启缓存注解支持 public class SkyApplication { public static void main(String[] args) { SpringApplication.run(SkyApplication.class, args); } }作用说明:EnableCaching注解启用 Spring 的缓存管理功能自动扫描并处理Cacheable、CacheEvict、CachePut等缓存注解配合 Redis 配置自动将缓存数据存储到 Redis2. Redis 依赖与配置依赖(pom.xml):dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-cache/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency配置(application.yml):yamlspring: redis: host: ${sky.redis.host} port: ${sky.redis.port} password: ${sky.redis.password} database: ${sky.redis.database}三、缓存读取机制C端文件:user/SetmealController.javaGetMapping(/list) ApiOperation(根据分类id查询套餐) Cacheable(cacheNames setmealCache, key #categoryId) // 核心注解 public ResultListSetmeal list(Long categoryId) { Setmeal setmeal new Setmeal(); setmeal.setCategoryId(categoryId); setmeal.setStatus(StatusConstant.ENABLE); // 只查询起售中的套餐 ListSetmeal list setmealService.list(setmeal); return Result.success(list); }Cacheable 注解解析属性值说明cacheNamessetmealCache缓存名称作为Key前缀key#categoryIdSpEL表达式使用方法参数作为缓存键value方法返回值自动缓存方法返回的ListSetmeal缓存Key生成规则完整Key格式: cacheNames::key 示例: setmealCache::100执行流程用户请求 → Cacheable 拦截 → 检查缓存 │ ├── 缓存存在 → 直接返回缓存数据不执行方法体 │ └── 缓存不存在 → 执行方法体 → 将返回值写入缓存 → 返回结果四、缓存失效机制Admin端文件:admin/SetmealController.java4.1 精准失效新增套餐PostMapping ApiOperation(新增套餐) CacheEvict(cacheNames setmealCache, key #setmealDTO.categoryId) public Result save(RequestBody SetmealDTO setmealDTO) { setmealService.saveWithDish(setmealDTO); return Result.success(); }失效策略: 只删除新增套餐所属分类的缓存4.2 全量失效删除/修改/状态变更// 批量删除 DeleteMapping CacheEvict(cacheNames setmealCache, allEntries true) public Result delete(RequestParam ListLong ids) { setmealService.deleteBatch(ids); return Result.success(); } // 修改套餐 PutMapping CacheEvict(cacheNames setmealCache, allEntries true) public Result update(RequestBody SetmealDTO setmealDTO) { setmealService.update(setmealDTO); return Result.success(); } // 起售停售 PostMapping(/status/{status}) CacheEvict(cacheNames setmealCache, allEntries true) public Result startOrStop(PathVariable Integer status, Long id) { setmealService.startOrStop(status, id); return Result.success(); }CacheEvict 注解解析属性值说明cacheNamessetmealCache缓存名称key#setmealDTO.categoryId精准删除指定键可选allEntriestrue删除该缓存名称下的所有条目beforeInvocation默认false方法执行后再删除缓存五、失效策略对比操作策略注解配置原因新增套餐精准失效key#setmealDTO.categoryId只影响当前分类删除套餐全量失效allEntriestrue无法确定影响范围修改套餐全量失效allEntriestrue分类可能改变状态变更全量失效allEntriestrue影响所有分类列表六、Spring Cache 工作原理解析6.1 注解处理流程┌────────────────────────────────────────────────────────────┐ │ Cacheable 执行流程 │ ├────────────────────────────────────────────────────────────┤ │ │ │ 1. 方法调用 │ │ │ │ │ ▼ │ │ 2. CacheInterceptor 拦截 │ │ │ │ │ ▼ │ │ 3. 根据 cacheNames key 生成缓存键 │ │ │ │ │ ▼ │ │ 4. 查询 CacheManager → Redis │ │ │ │ │ ├── 命中 → 返回缓存值不执行方法 │ │ │ │ │ └── 未命中 → 执行方法 → 将结果写入缓存 → 返回结果 │ │ │ └────────────────────────────────────────────────────────────┘6.2 缓存抽象层架构┌─────────────────────────────────────────────────────┐ │ Spring Cache 抽象层 │ ├─────────────────────────────────────────────────────┤ │ │ │ Cacheable / CacheEvict / CachePut │ │ │ │ │ ▼ │ │ CacheInterceptor (AOP切面) │ │ │ │ │ ▼ │ │ CacheManager (缓存管理器) │ │ │ │ │ ▼ │ │ RedisCacheManager (Redis实现) │ │ │ │ │ ▼ │ │ RedisTemplate │ │ │ │ │ ▼ │ │ Redis Server │ │ │ └─────────────────────────────────────────────────────┘七、与菜品缓存的对比维度菜品缓存 (Dish)套餐缓存 (Setmeal)实现方式手动 RedisTemplate 操作Spring Cache 注解缓存键格式dish_{categoryId}setmealCache::{categoryId}读取方式redisTemplate.opsForValue().get(key)Cacheable注解自动处理失效方式cleanCache(pattern)手动方法CacheEvict注解自动处理代码侵入性需要手动编写缓存逻辑零侵入注解声明式扩展性需要手动维护支持多种缓存后端切换至此缓存套餐的代码已经开发完毕下一期将为大家带来对购物车进行操作的代码开发讲解