《苍穹外卖》项目学习记录-Day7缓存菜品

我们优先去读取缓存数据,如果有就直接使用,如果没有再去查询数据库,查出来之后再放到缓存里去。

微信小程序根据分类来展示菜品,所以每一个分类下边的菜品对应的就是一份缓存数据,这样的话当我们使用这个数据的时候,就可以一次性的把这个分类下面的缓存数据给它加载出来。Redis保存数据是key-value结构,我们可以使用分类的id来作为我们缓存的key,而value则是分类下面这些具体的菜品数据,这些菜品数据可以使用String字符串来进行保存。Redis当中的数据类型跟Java当中的数据类型并不是完全对应的,也就是说Java当中任何一个对象,都可以给它转成Redis当中的String字符串来进行存储。从Java对象这个角度来考虑,这些一个分类下面的具体菜品数据可以用List集合进行存储,然后把这个集合进行序列化,最终转成Redis的一个字符串来存储。

数据库中菜品数据有变更时清理缓存数据,如果不清理会造成我们这个数据的不一致,比如说在商家管理端把某一个菜品的价格改了,如果不清理对应的缓存,因为管理端改了菜品价格修改的是MySQL数据库里面数据,但是小程序展示出来的是读取缓存Redis里面的数据,Redis里面的数据没有改,所以小程序里面展示的还是原来的价格。

1.查询redis中是否存在菜品数据。放进去是什么类型的取出来就是什么类型的,放进去是List<DishVo>类型的所以取出来要强转成List<DishVo>类型的。

2.如果存在,直接返回,无须查询数据库。

3.如果不存在,查询数据库,将查询到的数据放入redis中。

数据缓存到了Redis里

使用Redis缓存数据要保证数据的一致性,这个数据的一致性主要是体现在我们MySQL数据库当中的数据跟Redis缓存当中的数据必须是一致的,也就是说当我们MySQL数据库当中的数据发生变更时,我们需要及时的把Redis缓存的数据清理掉,然后它重新去查MySQL数据库,这样的话就一致了。

新增菜品我们可以精确的去清理掉分类id对应的缓存数据。

菜品批量删除有可能会删除多个菜品,而多个菜品可能属于某一个分类下边,也可能是某些不同分类下边的菜品,也就是它可能会影响到多个key,影响到哪个key,需要查询MySQL数据库才会知道。这样太复杂,所以如果执行了菜品批量删除,我们就把所有的缓存数据清理掉,也就是dish_开头的数据都给它清理掉。删除的时候不能识别通配符,所以我们先把所有的key查询出来,然后再去删除。

修改菜品如果是修改了分类,那就影响到了两份缓存数据,也就是原先的分类会少一个,修改后的分类会多一个,如果修改的是菜品名称,价格这些属性则只会影响一份缓存数据。这样看来修改菜品有可能会影响一份缓存数据,有可能会影响两份缓存数据,修改操作并不是常规操作,一般很少去修改,所以我们这里简单的处理了,统一清理掉所有的缓存数据

菜品起售停售,需要根据菜品id把对应的数据查出来,菜品数据里面就有分类id,这样就可以动态的把key构造出来,这样就可以清理某一个key,也就是菜品起售停售对应的缓存数据,这样去实现还要额外去查询数据,所以这里我们统一清理所有的缓存数据。

java 复制代码
package com.sky.controller.admin;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Set;

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {
    @Autowired
    private DishService dishService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增菜品
     * @param dishDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增菜品")
    public Result save(@RequestBody DishDTO dishDTO) {
        log.info("新增菜品:{}", dishDTO);
        dishService.saveWithFlavor(dishDTO);
        //清理缓存数据
        String key = "dish_" + dishDTO.getCategoryId();
        cleanCache(key);
        return Result.success();
    }

    /**
     * 菜品分页查询
     *
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("菜品分页查询")
    public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {
        log.info("菜品分页查询:{}", dishPageQueryDTO);
        PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
        return Result.success(pageResult);
    }

    /**
     * 菜品批量删除
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("菜品批量删除")
    public Result delete (@RequestParam List<Long> ids){
        log.info("菜品批量删除,{}",ids);
        dishService.deleteBatch(ids);
        //将所有的菜品缓存数据清理掉,所有以dish_开头
       cleanCache("dish_*");
        return Result.success();
    }

    /**
     * 根据id查询菜品和对应的口味数据
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询菜品")
    public Result<DishVO> getById(@PathVariable Long id){
        log.info("根据id查询菜品:{}",id);
        DishVO dishVO = dishService.getByIdWithFlavor(id);
        return Result.success(dishVO);
    }

    /**
     * 修改菜品
     * @param dishDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改菜品")
    public Result update(@RequestBody DishDTO dishDTO){
    log.info("修改菜品:{}",dishDTO);
    dishService.updateWithFlavor(dishDTO);
    //将所有的菜品缓存数据清理掉,所有以dish_开头
    cleanCache("dish_*");
    return Result.success();
    }

    /**
     * 菜品的起售停售
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("菜品的起售停售")
    public Result<String> startOrStop(@PathVariable Integer status,Long id){
        log.info("菜品的起售停售:{},{}",status == 1 ? "起售" : "停售",id);
        dishService.startOrStop(status,id);
        //将所有的菜品缓存数据清理掉,所有以dish_开头的key
        cleanCache("dish_*");
        return Result.success();
    }
    /**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<Dish>> list(Long categoryId) {
        List<Dish> list = dishService.list(categoryId);
        return Result.success(list);
    }

    /**
     * 清理缓存数据
     * @param patten
     */
    private void cleanCache(String patten){
        Set keys = redisTemplate.keys(patten);
        redisTemplate.delete(keys);
    }
}

·测试

我们停售之后也把相应的缓存数据清理掉,然后重新查询数据库,它就变成这个样子了。

相关推荐
西岸行者11 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意11 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码11 天前
嵌入式学习路线
学习
毛小茛11 天前
计算机系统概论——校验码
学习
babe小鑫11 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms11 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下11 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。11 天前
2026.2.25监控学习
学习
im_AMBER11 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J11 天前
从“Hello World“ 开始 C++
c语言·c++·学习