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

缓存菜品操作

一:问题说明

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

二:实现思路 

通过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 {@Autowiredprivate DishService dishService;@Autowiredprivate RedisTemplate redisTemplate;/*** 根据分类id查询菜品* @param categoryId* @return*/@GetMapping("/list")@ApiOperation("根据分类id查询菜品")public Result<List<DishVO>> selectById(Long categoryId){log.info("根据分类id查询菜品:{}",categoryId);//构造redis中的key ,规则:dish_分类idString 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 {@Autowiredprivate DishService dishService;@Autowiredprivate 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注解

相关文章:

缓存菜品操作

一&#xff1a;问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大。 二&#xff1a;实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; 每个分…...

达梦数据库常用命令整理

1.数据库自身信息 1.1 查询实例信息 SQL> select name inst_name from v$instance;行号 INST_NAME ---------- --------- 1 DMSERVER已用时间: 11.211(毫秒). 执行号:15.1.2 查询数据库当前状态 SQL> select status$ from v$instance;行号 STATUS$ -…...

Vue 组件的三大组成部分

Vue 组件通常由三大组成部分构成&#xff1a;模板&#xff08;Template&#xff09;、脚本&#xff08;Script&#xff09;、样式&#xff08;Style&#xff09; 模板部分是组件的 HTML 结构&#xff0c;它定义了组件的外观和布局。Vue 使用基于 HTML 的模板语法来声明组件的模…...

MoneyPrinter中的文字转声音国内替换方案

背景&#xff1a; 在进行MoneyPrinter项目国内环境搭建中&#xff0c;发现框架本身的TikTok文字转语音部分的代码已经不能用了&#xff0c;最好是能够找到国内网站的替换方案。 实现&#xff1a; 感谢网站&#xff1a;https://www.text-to-speech.cn/ 代码&#xff1a; # -*…...

消除试卷手写笔迹的软件免费的有哪些?这几款都不错

消除试卷手写笔迹的软件免费的有哪些&#xff1f;在数字化学习的浪潮中&#xff0c;学生们越来越频繁地利用电子设备来完成学习任务。然而&#xff0c;当纸质试卷需要被数字化并再次利用时&#xff0c;如何高效地消除手写笔迹便成为了一个有待解决的问题。那么&#xff0c;今天…...

智能创作时代:AI 如何重塑内容生成游戏规则

文章目录 前言一&#xff1a;自动化内容生成文章生成视频制作音频创作 二&#xff1a;内容分发与推广智能推荐系统社交媒体优化 三&#xff1a;内容分析与优化数据分析用户反馈质量控制 结语 前言 在数字化时代的浪潮中&#xff0c;内容生产与消费已成为信息传播的核心。随着人…...

大数据------JavaWeb------Tomcat(完整知识点汇总)

Web服务器——Tomcat Web服务器定义 它是一个应用程序&#xff08;软件&#xff09;&#xff0c;对HTTP协议的操作进行封装&#xff0c;使得程序员不必直接对协议进行操作&#xff0c;让Web开发更便捷 Web服务器主要功能 封装HTTP协议操作&#xff0c;简化开发将Web项目部署到…...

LMDeploy笔记

随谈模型部署 模型部署包含的内容很多&#xff0c;来聊聊。 访存bottleneck 首先&#xff0c;基于transformer的计算是访存密集型任务。 so? 过去&#xff0c;我们表达模型的性能&#xff0c;通常会用ops&#xff0c;macs这些指标,也计算量来衡量模型的推理时间&#xff…...

Unity 状态机

文章目录 前言一、状态机二、应用1、场景切换2、人物行为切换3、宝箱、机关切换4、AI 三、人物行为总结 前言 提到Unity状态机&#xff0c;接触不久的开发者会想到Unity的动画状态机&#xff0c;而对于老油条来说&#xff0c;可能会回忆起自己实现的动画状态机。当然&#xff…...

一毛钱不到的FH8208C单节锂离子和锂聚合物电池一体保护芯片

前言 目前市场上电池保护板&#xff0c;多为分体方案&#xff0c;多数场合使用没有问题&#xff0c;部分场合对空间有进一步要求&#xff0c;或者你不想用那么多器件&#xff0c;想精简一些&#xff0c;那么这个芯片就很合适&#xff0c;对于充电电池来说&#xff0c;应在使用…...

python数据可视化:显示两个变量间的关系散点图scatterplot()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 python数据可视化&#xff1a; 显示两个变量间的关系 散点图 scatterplot() [太阳]选择题 请问关于以下代码表述错误的选项是&#xff1f; import seaborn as sns import matplotlib.pyplot …...

【QT教程】QT6硬件高级编程入门 QT硬件高级编程

QT6硬件高级编程入门 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看…...

Android 蓝牙实战——蓝牙电话通话状态同步(二十四)

前面分析了蓝牙电话通话状态的广播,我们可以在蓝牙电话中实时监听蓝牙电话的状态,但如果是其他音乐类 APP 呢,在播放的时候也需要知道当前是否有通话正在进行,但是有完全没必要实时监听电话的状态,这就需要一个获取通话状态的方法。 一、通话状态处理 1、CallsManager …...

docker 指定根目录 迁移根目录

docker 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、启动docker程序前就手动指定docker根目录为一个大的分区(支持动态扩容)&#xff0c;事前就根本上解决根目录空间不够问题3.1.0、方法思路3.1.1、docker官网安装文档3.1.2、下载docker安装包3.1.3、安装doc…...

React 项目报错解决办法收录

React 使用 引入文件报错 (react 别名配置craco) react &#xff0c;vue 初始项目都是不支持 别名引入文件的。 vue 一般项目初始化的时候会 在 vue.config.js 文件中配置好&#xff0c;所以不需要我们自己配置react 初始化的时候是没有配置的&#xff0c; 需要我们自己配置 …...

Linux专题-Makefile(1)

1.Makefile中的注释使用 # 2. Makefile中的静默执行。 makefile中&#xff0c;默认情况下执行一行命令前会先把这一行命令打印出来&#xff0c;然后再执行这条命令。如果不想看到打印的命令&#xff0c;则可以使用静默执 行的功能&#xff0c;即仅打印出命令执行的结果。使用方…...

机器学习算法应用——CART决策树

CART决策树&#xff08;4-2&#xff09; CART&#xff08;Classification and Regression Trees&#xff09;决策树是一种常用的机器学习算法&#xff0c;它既可以用于分类问题&#xff0c;也可以用于回归问题。CART决策树的主要原理是通过递归地将数据集划分为两个子集来构建决…...

Sqli-labs第五,六关

目录 首先找到他们的闭合方式 操作 总结&#xff1a; 第五关根据页面结果得知是字符型但是和前面四关还是不一样是因为页面虽然有东西。但是只有对于请求对错出现不一样页面其余的就没有了。这个时候我们用联合注入就没有用&#xff0c;因为联合注入是需要页面有回显位。如果…...

上海AI Lab开源首个可替代GPT-4V的多模态大模型

与开源和闭源模型相比&#xff0c;InternVL 1.5 在 OCR、多模态、数学和多轮对话等 18 个基准测试中的 8 个中取得了最先进的结果。 上海AI Lab 推出的 InternVL 1.5 是一款开源的多模态大语言模型 (MLLM)&#xff0c;旨在弥合开源模型和专有商业模型在多模态理解方面的能力差距…...

Python教程:一文了解PageObject模式

PageObject 模式是一种用于测试自动化的设计模式&#xff0c;它将页面的功能和页面的实现分开&#xff0c;提高了代码的可维护性和可重用性。本文将从基础概念开始&#xff0c;逐步介绍 Python 中的 PageObject 模式&#xff0c;并提供详细的代码示例。 1. 什么是 PageObject 模…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...