Day07 学什么
Day07 主要做两块能力建设:缓存商品(菜品/套餐) + 购物车。
你最终要达到的效果:
- 用户端展示菜品/套餐时:优先走 Redis 缓存,减数据库压力(访问更快)。
- 用户端购物车:能 添加、查看、清空。
推荐学习顺序
0)先把“验收点”想清楚(你写完要怎么证明它对了)
- 缓存:第一次查某分类 有 SQL,第二次查同分类 没 SQL,Redis 里能看到 key。
- 数据变更:后台改菜品/套餐后,再访问用户端时能重新查库并回填缓存(说明缓存被清掉了)。
(讲义也强调用 “控制台 SQL + Redis 数据变化” 来验证)
1. 缓存菜品(RedisTemplate 手写缓存)
1.1 为什么要缓存
用户端小程序菜品列表如果每次都查数据库,访问量大时 DB 压力上来,响应会慢。
1.2 缓存策略(非常重要:你要背下来)
- 按分类缓存:每个分类一份缓存(key 通常
dish_分类id) - 数据变更要清缓存:新增/修改/删除/起售停售后,清理对应缓存(或干脆清
dish_*)
1.3 用户端 DishController:先查 Redis,没命中再查 DB 回填
- key:
dish_ + categoryId redisTemplate.opsForValue().get(key)命中直接返回- 未命中:查库
dishService.listWithFlavor(dish),再set(key, list)
你写的时候只要盯住:读缓存 → 读库 → 写缓存 这条链路。
1.4 管理端 DishController:封装 cleanCache(pattern) 清理缓存
讲义提供了一个抽取方法:keys(pattern) + delete(keys),然后在新增/修改/删除/起售停售里调用。
你最容易踩的坑:
keys("dish_*")在大 key 场景会阻塞 Redis(生产上要谨慎)。课程项目里可以先这样做,后面你可以自己升级成:记录分类 key、精准删除、或用消息/延迟双删等。RedisTemplate的序列化:如果你发现 Redis 里是乱码/反序列化失败,优先检查 RedisTemplate 的 key/value serializer 配置(课程基础工程一般已配好)。
2. 缓存套餐(Spring Cache 注解式缓存)
这块重点是:用注解完成缓存读写/清理,比手写更优雅。常见注解:@Cacheable / @CachePut / @CacheEvict,启动类加 @EnableCaching。
2.1 实现步骤(你按清单逐条打勾)
- 引入 cache + redis 依赖(讲义说已实现/或给了坐标)
- 启动类加
@EnableCaching开启注解缓存 - 用户端 SetmealController
list上加@Cacheable(cacheNames="setmealCache", key="#categoryId") - 管理端增删改/起售停售:用
@CacheEvict清理缓存(常见:allEntries = true)
你最容易卡的点:
key写法:#categoryId是方法参数;如果你写成#setmealDTO.categoryId(保存时)要确认参数名/字段路径正确(讲义里就是这么用的)。allEntries=true:简单粗暴但正确;后面可以优化为按分类精准清理。
3. 购物车(添加 / 查看 / 清空)
3.1 表结构与规则(先搞懂,再写代码)
购物车表 shopping_cart 的关键点:购物车属于用户,菜品/套餐二选一存(dish_id 或 setmeal_id),同一商品不重复插多行,只增 number。
3.2 添加购物车:/user/shoppingCart/add
-
DTO:
dishId / setmealId / dishFlavor(口味) -
Controller 调 Service 的 add 方法
-
Service 核心逻辑(你写代码就照这段心智模型):
- 只查当前用户:
shoppingCart.setUserId(BaseContext.getCurrentId()) - 根据 userId + dishId/setmealId + dishFlavor 查是否已有
- 有:
number + 1更新 - 无:查 dish/setmeal 填充 name/image/amount,插入新记录、number=1
- 只查当前用户:
你最容易踩的坑:
- “同一商品”的判定条件要包含 口味 dishFlavor(否则不同口味会被当成同一条合并)。
- BaseContext 里的 currentId 必须在登录/拦截器链路里正确设置(否则 userId 为空会查出全表或插错数据)。
3.3 查看购物车:/user/shoppingCart/list
Controller 直接返回 shoppingCartService.showShoppingCart();Service 按当前 userId 查列表即可。
3.4 清空购物车:/user/shoppingCart/clean
本质就是:delete from shopping_cart where user_id = ?。
一口气做完的“实操清单”
- ✅ 用户端菜品列表:加 Redis 缓存(命中直接返回;未命中查库回填)
- ✅ 管理端菜品:新增/修改/删除/起售停售后清缓存(至少做到
dish_*清理) - ✅ 启动类:
@EnableCaching - ✅ 用户端套餐:
@Cacheable - ✅ 管理端套餐:
@CacheEvict - ✅ 购物车:add / list / clean 三个接口跑通