当前位置: 首页 > article >正文

《苍穹外卖》项目学习记录-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,也就是菜品起售停售对应的缓存数据,这样去实现还要额外去查询数据,所以这里我们统一清理所有的缓存数据。

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);
    }
}

·测试

 

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

 


http://www.kler.cn/a/527126.html

相关文章:

  • Vue+Echarts 实现青岛自定义样式地图
  • TCL C++开发面试题及参考答案
  • linux用户管理
  • 步进电机加减速公式推导
  • 【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)
  • Spring MVC 综合案例
  • pytorch图神经网络处理图结构数据
  • Git进阶之旅:分支管理策略
  • 【华为OD-E卷 - 字符串化繁为简 100分(python、java、c++、js、c)】
  • 计算机网络一点事(23)
  • minimind - 从零开始训练小型语言模型
  • 树莓派入门笔记(二)最常用的树莓派 Linux 命令及说明_树莓派系统命令
  • PostgreSQL TRUNCATE TABLE 操作详解
  • AVL搜索树
  • 商品列表及商品详情展示
  • 通过想像,见证奇迹
  • 【gRPC-gateway】初探grpc网关,插件安装,默认实现,go案例
  • Mysql进阶学习
  • 最新 Android 热门开源项目公布
  • 稀疏混合专家架构语言模型(MoE)
  • 【4Day创客实践入门教程】Day4 迈向高手之路——进一步学习!
  • .cc扩展名是什么语言?C语言必须用.c为扩展名吗?主流编程语言扩展名?Java为什么不能用全数字的文件名?
  • 七、深入了解SpringBoot的配置文件
  • 代随(138):单调栈:一维接雨水
  • 如何将IP切换到海外:详细指南
  • WebSocket使用及优化(心跳机制与断线重连)_websocket timeout