缓存菜品操作

news2024/10/6 21:28:24

一:问题说明

用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。

二:实现思路 

通过Redis来缓存菜品数据,减少数据库查询操作。

缓存逻辑分析:

  • 每个分类下的菜品保存一份缓存数据
  • 数据库中菜品数据有变更时清理缓存数据 

 三:具体的代码实现:

DishControll层(用户端):

我们需要在dishcontrol层加入缓存处理

  1. 注入redis
  2. 构造redis的key(根据我们上面的规则,redis中的key是为dish_ + 分类的id)
  3. 查询redis中是否有这个菜品
  4. 如果有,直接返回
  5. 如果没有,请求数据库,并且把这个菜品放到redis中
package com.sky.controller.user;

import com.sky.constant.StatusConstant;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController("userDishController")
@RequestMapping("/user/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {
    @Autowired
    private DishService dishService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 根据分类id查询菜品
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<DishVO>> selectById(Long categoryId){
        log.info("根据分类id查询菜品:{}",categoryId);
        //构造redis中的key ,规则:dish_分类id
        String key = "dish_" + categoryId;
        //查询redis中是否又菜品数据
        List<DishVO> dishVOList = (List<DishVO>) redisTemplate.opsForValue().get(key);
        if(dishVOList != null|| dishVOList.size()>0){
            //如果存在,直接返回,不用查询数据库
            return Result.success(dishVOList);
        }
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);
        /*
        这里的dish对象的作用就是充当一个判断条件
        我们返回的是一个List<DishVO>对象,那这个对象的条件是什么呢?
        是:这个dish的分类id和这个categoryId相等,并且呢,还得是在起售的产品
         */
        List<DishVO> list = dishService.listWithFlavor(dish);
        //如果不存在,查询数据库,将查询到的数据放到redis中
        redisTemplate.opsForValue().set(key,list);
        return Result.success(list);
    }
}

 清理缓存:

上面的操作有一个很大的问题就是,如果我们修改了数据库里面的数据,怎么同步到redis中

这就涉及到这个请求缓存的操作了

我们的解决方法是在服务端DishControll层(因为客户肯定不可能修改我的数据,只有客户端可以)进行清理缓存的操作。

那这个时候又要具体分析了,什么样的方法需要清理缓存,是不是对数据库能进行修改的操作嘞

(增删改)

所以我们在dishcontroll层对这三类方法采用的方法是:

只要你对这个数据库进行了操作,我们直接把相关的缓存全部删掉

 DishControll层(服务端):

package com.sky.controller.admin;


import com.github.pagehelper.Page;
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.ArrayList;
import java.util.List;
import java.util.Set;

@RestController("adminDishController")
@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.insert(dishDTO);
        //清理缓存数据
        String pattern = "dish_"+dishDTO.getCategoryId();
        cleanCache(pattern);
        return Result.success();
    }

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

    /**
     * 批量删除菜品
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("批量删除菜品")
    public Result delete(@RequestParam List<Long> ids){
        log.info("批量删除菜品:{}",ids);
        dishService.deletebatch(ids);
        //清理缓存数据
        String pattern = "dish_*";
        cleanCache(pattern);
        return Result.success();
    }


    /**
     * 根据id查询菜品
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询菜品接口")
    public Result<DishVO> selectById(@PathVariable Long id){
        log.info("根据id查询菜品:{}",id);
        DishVO dishVO = dishService.selectById(id);
        return Result.success(dishVO);
    }

    /**
     * 修改菜品
     * @param dishDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改菜品接口")
    public Result update(@RequestBody DishDTO dishDTO){
        log.info("修改菜品:{}",dishDTO);
        dishService.updateWithFlavor(dishDTO);
        //清理缓存数据
        String pattern = "dish_*";
        cleanCache(pattern);
        return Result.success();
    }

    /**
     * 菜品起售停售
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("菜品起售停售")
    public Result<String> startOrStop(@PathVariable Integer status, Long id){
        dishService.startOrStop(status,id);
        //清理缓存数据
        String pattern = "dish_*";
        cleanCache(pattern);
        return Result.success();
    }

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

四:Spring Cache框架:

Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能

Spring Cache中的常用注解:

Spring Cache入门小程序:

 @EnableCaching注解:

直接加在启动类上就行。

@Slf4j
@SpringBootApplication
@EnableCaching//启动缓存注解
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}
 @CachePut注解:

(cacheput这个注解一般加在插入数据的方法上)

    @PostMapping
    @CachePut(cacheNames = "userNames",key = "#user.id")
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }

 这里的cacheNames其实就是这个缓存的名字。

key的生成:cacheNames::#user.id

我们这个使用的时候这个返回值的id,

    @Insert("insert into spring_cache_demo.user(name,age) values (#{name},#{age})")
    @Options(useGeneratedKeys = true,keyProperty = "id")
    void insert(User user);

这里需要注意的是,我们需要在mapper层中的插入方法下加入将id返回这个一个选项功能。

因为id是自增的,所以不一定要从前端传。 

@Cacheable注解:
    @GetMapping
    @Cacheable(cacheNames = "userNames",key = "#id")
    public User getById(Long id){
        User user = userMapper.getById(id);
        return user;
    }

这里的两个参数就和刚刚的@CachePut的参数一样就行。

下面是我查询了一个id为1的数据,因为id为1的数据还没放到缓存中,所以还是从数据库里面查的

 然后我查询了一个id为2的数据,控制台没有任何反应。

并且这个Cacheable注解还会把数据直接插入缓存中:

下面是我又查了一次id为1的数据。

控制台没有任何的反应

 @Cacheable 这个注解使用了一个代理对象的技术(AOP),

就是当你给controller层的方法加了这个Cacheable注解,其实这个框架就会创建一个代理对象,我们查询的数据会先被这个代理对象接收,如果这个代理对象没查到,才会交给这个方法来查。

具体的体现就是,如果这个数据在这个缓存中,就连这个select的方法都不会调用(用断点的方式可以测出)

 @CacheEvict注解:
    @DeleteMapping
    @CacheEvict(cacheNames = "userNames",key = "#id")
    public void deleteById(Long id){
        userMapper.deleteById(id);
    }

这个注解主要的作用就是帮我们清楚缓存,我们直接在发一条sql语句,同时能删除数据库中和redis中的数据。 

@CacheEvict(cacheNames = "setmealCache",allEntries = true)

如果指定这个allEntries = true,那就代表把所有的缓存都给删掉

 Spring Cache缓存套餐具体思路:

具体的实现思路如下:

  • 导入Spring Cache和Redis相关maven坐标
  • 在启动类上加入@EnableCaching注解,开启缓存注解功能
  • 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
  • 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1660253.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【UnityRPG游戏制作】Unity_RPG项目_玩法相关※

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

【基础算法总结】滑动窗口二

滑动窗口二 1.水果成篮2.找到字符串中所有字母异位词3.串联所有单词的子串4.最小覆盖子串 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.水…

Dbeaver network unavailable due to certificate issue

场景&#xff1a;出现在DBeaver连接数据库下载驱动的时候 解决&#xff1a; 别勾选就可以了

Java的基本语法

文章目录 Java语言的一些基本语法要点&#xff1a;Java语言的一些进阶概念和特性&#xff1a;Java代码示例基础示例1. Hello World2. 计算两个数的和 进阶示例1. 使用Lambda表达式过滤列表2. 实现一个简单的泛型类3. 使用多线程打印数字 异常处理示例捕获并处理异常 接口使用示…

【前端】HTML实现个人简历信息填写页面

文章目录 前言一、综合案例&#xff1a;个人简历信息填写页面 前言 这篇博客仅仅是对HTML的基本结构进行了一些说明&#xff0c;关于HTML的更多讲解以及CSS、Javascript部分的讲解可以关注一下下面的专栏&#xff0c;会持续更新的。 链接&#xff1a; Web前端学习专栏 下面我对…

Python专题:六、循环语句(2)

for循环语句 列表可以简单的理解为&#xff1a; 顺序保存的若干元素 注释&#xff1a;变量largest&#xff0c;循环语句for&#xff0c;还有二层缩进八个空格 依次取出counts&#xff08;列表&#xff09;里的数字&#xff0c;并赋予给x&#xff0c;判断x和largest数值大小。…

深度学习之视觉特征提取器——AlexNet

AlexNet 参考资料&#xff1a; &#xff08;1&#xff09;ImageNet十年历任霸主之AlexNet - 知乎 (zhihu.com) &#xff08;2&#xff09;AlexNet - Wikipedia 引入 AlexNet在2012年以第一名在Top-1分类精度霸榜ImageNet&#xff0c;并超过第二名近10个百分点&#xff0c;…

OpenCV-基于累计直方图的中值滤波算法

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 实现原理 基于累计直方图的中值滤波算法是一种图像处理技术&#xff0c;用于去除图像中的噪声。它利用了像素值的频数分布&#…

图片过大怎么处理变小?在线编辑图片工具推荐

在各种平台进行图片上传时&#xff0c;经常会遇到由于图片过大而无法成功上传的问题&#xff0c;为了顺利进行下一步操作&#xff0c;我们需要将图片进行缩小处理&#xff0c;通常情况下&#xff0c;我们可以使用各种软件工具来对图片进行缩小&#xff0c;如何快速有效地调整图…

自动驾驶系统中的端到端学习

资料下载-《自动驾驶系统中的端到端学习&#xff08;2020&#xff09;》https://mp.weixin.qq.com/s/ttNpsn7qyVWvDMZzluU_pA 近年来&#xff0c;卷积神经网络显著提高了视觉感知能力。实现这一成功的两个主要因素是将简单的模块组合成复杂的网络和端到端的优化。然而&#xf…

源代码防泄密-文档加密与沙盒加密的区别

研发人员比普通办公人员要精通电脑&#xff0c;除了常见的网络&#xff0c;邮件&#xff0c;U盘&#xff0c;QQ等数据扩散方法外&#xff0c;外设中转对研发人员来说轻而易举&#xff1a; — 对于嵌入式开发场景&#xff0c;可以通过串口&#xff0c;U口&#xff0c;网口把代码…

美团二面:SpringBoot读取配置优先级顺序是什么?

引言 Spring Boot作为一种轻量级的Java应用程序框架&#xff0c;以其开箱即用、快速搭建新项目的特性赢得了广大开发者的青睐。其核心理念之一就是简化配置过程&#xff0c;使开发者能够快速响应复杂多变的生产环境需求。为了实现这一点&#xff0c;Spring Boot支持丰富的外部…

OpenVoiceV2本地部署教程,苹果MacOs部署流程,声音响度统一,文字转语音,TTS

最近OpenVoice项目更新了V2版本&#xff0c;新的模型对于中文推理更加友好&#xff0c;音色也得到了一定的提升&#xff0c;本次分享一下如何在苹果的MacOs系统中本地部署OpenVoice的V2版本。 首先下载OpenVoiceV2的压缩包&#xff1a; OpenVoiceV2-for-mac代码和模型 https:…

Minio(官方docker版)容器部署时区问题研究记录

文章目录 感慨&概述补充&#xff1a;MINIO_REGION和容器时间的关系 问题一&#xff1a;minio容器和本地容器时间不一致问题说明原因探究解决方法结果验证 问题二&#xff1a;minio修改时间和本地查询结果不一致具体问题原因探究解决办法时间转化工具类调用测试和验证上传文…

4. 从感知机到神经网络

目录 1. 从感知机到神经网络 2. 最简单的神经网络 3. 激活函数的引入 1. 从感知机到神经网络 之前章节我们了解了感知机&#xff0c;感知机可以处理与门、非与门、或门、异或门等逻辑运算&#xff1b;不过在感知机中设定权重的工作是由人工来做的&#xff0c;而设定合适的&a…

障碍物识别软件的优缺点

在这个科技与人文关怀交织的时代&#xff0c;一款基于激光雷达技术的障碍物识别软件正悄然为视障人士的日常生活带来一场革命性的改变。这一款叫做“蝙蝠避障”的软件利用先进科技的力量&#xff0c;为盲人出行铺设了一条更加安全、独立的道路。今天&#xff0c;让我们从资深记…

智能呼叫中心客服系统:企业客户服务的新引擎

在如今商业竞争激烈的大环境下&#xff0c;企业的客户服务需求已不仅仅局限于简单的沟通。随着科技的进步&#xff0c;客户对于高效、智能的交互体验有着更高的期待。为了满足这些需求&#xff0c;智能呼叫中心客服系统应运而生&#xff0c;成为企业提升客户服务质量、优化客户…

vs Code配置python环境

vs Code 作为一款轻量级的源代码编辑IDE,其以轻量级和易用性著称&#xff0c;笔者今天记录分享下在其上面配置python环境&#xff0c;因为 笔者最近在学习了解Python&#xff0c;其实关于python的IDE有 pyCharm,但后期还需要进行其他语言的开发&#xff0c;索性就弄个集成度比较…

Python专题:十、字典(1)

数据类型:字典,是一个集合性质的数据类型 字典的初始化 字典{关键字:数值} 新增元素 修改元素 字典元素访问 字典[关键字} in 操作符 字典关键字检测 字典元素遍历 ①遍历关键字

每日OJ题_记忆化搜索②_力扣62. 不同路径(三种解法)

目录 力扣62. 不同路径 解析代码1_暴搜递归&#xff08;超时&#xff09; 解析代码2_记忆化搜索 解析代码3_动态规划 力扣62. 不同路径 62. 不同路径 难度 中等 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器…