缓存商品、购物车(day07)
缓存菜品
问题说明
问题说明:用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。
结果: 系统响应慢、用户体验差
实现思路
通过Redis来缓存菜品数据,减少数据库查询操作。
缓存逻辑分析:
- 每个分类下的菜品保存一份缓存数据
- 数据库中菜品数据有变更时清理缓存数据
代码开发
修改用户端接口 DishController 的 list 方法,加入缓存处理逻辑:
为了保证数据库和Redis中的数据保持一致,修改管理端接口 DishController 的相关方法,加入清理缓存逻辑。
修改管理端接口 DishController 的相关方法,加入清理缓存的逻辑,需要改造的方法:
- 新增菜品
- 修改菜品
- 批量删除菜品
- 起售、停售菜品
抽取清理缓存的方法:

调用清理缓存的方法,保证数据一致性:
调用清理缓存的方法,保证数据一致性:
调用清理缓存的方法,保证数据一致性:

功能测试
可以通过如下方式进行测试:
• 查看控制台 sql• 前后端联调• 查看 Redis 中的缓存数据
缓存套餐
Spring Cache
介绍
Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如:
- EHCache
- Caffeine
- Redis(常用)
常用注解:
在 SpringCache 中提供了很多缓存操作的注解,常见的是以下的几个:
在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存支持即可。
例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。
入门案例
入门案例:导入资料中的初始工程,在此基础上加入Spring Cache注解即可
导入基础工程: 底层已使用 Redis 缓存实现
基础环境的代码,在我们今天的资料中已经准备好了, 大家只需要将这个工程导入进来就可以了。导入进来的工程结构如下:

数据库准备:
创建名为spring_cache_demo数据库,将springcachedemo.sql脚本直接导入数据库中。

1、引导类上加@EnableCaching:
package com.itheima;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;@Slf4j
@SpringBootApplication
@EnableCaching //开启缓存注解功能
public class CacheDemoApplication {public static void main(String[] args) {SpringApplication.run(CacheDemoApplication.class,args);log.info("项目启动成功...");}
}
2). @CachePut注解
@CachePut 说明:
- 作用: 将方法返回值,放入缓存
- value: 缓存的名称, 每个缓存名称下面可以有很多key
- key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法
在save方法上加注解@CachePut
当前 UserController 的 save 方法是用来保存用户信息的,我们希望在该用户信息保存到数据库的同时,也往缓存中缓存一份数据,我们可以在 save 方法上加上注解 @CachePut,用法如下:
/*** CachePut:将方法返回值放入缓存* value:缓存的名称,每个缓存名称下面可以有多个key* key:缓存的key*/@PostMapping@CachePut(cacheNames = "userCache",key = "#user.id") //如果使用Spring Cache缓存数据,key的生成:userCache::1//@CachePut(cacheNames = "userCache",key = "#result.id") //对象导航//@CachePut(value = "userCache", key = "#p0.id")//p0,第一个参数;p1,第二个参数//@CachePut(value = "userCache", key = "#a0.id")//a0,第一个参数;a1,第二个参数//@CachePut(value = "userCache", key = "#root.args[0].id")//root.args[0],第一个参数public User save(@RequestBody User user){userMapper.insert(user);return user;}
说明: key的写法如下
- #user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ;
- #result.id : #result代表方法返回值,该表达式 代表以返回对象的id属性作为key ;
- #p0.id:#p0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
- #a0.id:#a0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
- #root.args[0].id:#root.args[0]指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
启动服务,通过swagger接口文档测试,访问UserController的save()方法
3). @Cacheable注解
@Cacheable 说明:
- 作用: 在方法执行前,spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
- value: 缓存的名称,每个缓存名称下面可以有多个key
- key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法
在getById上加注解@Cacheable
/*** Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据, *调用方法并将方法返回值放到缓存中* value:缓存的名称,每个缓存名称下面可以有多个key* key:缓存的key*/@Cacheable(cacheNames = "userCache",key = "#id")@GetMappingpublic User getById(Long id){User user = userMapper.getById(id);return user;}
重启服务,通过swagger接口文档测试,访问UserController的getById()方法
第一次访问,会请求我们controller的方法,查询数据库。后面再查询相同的id,就直接从Redis中查询数据,不用再查询数据库了,就说明缓存生效了。
4). @CacheEvict注解
@CacheEvict 说明:
- 作用: 清理指定缓存
- value: 缓存的名称,每个缓存名称下面可以有多个key
- key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法
在 delete 方法上加注解@CacheEvict
@CacheEvict(cacheNames = "userCache",key = "#id")//删除某个key对应的缓存数据@DeleteMappingpublic void deleteById(Long id){userMapper.deleteById(id);}@CacheEvict(cacheNames = "userCache",allEntries = true)//删除userCache下所有的缓存数据@DeleteMapping("/delAll")public void deleteAll(){userMapper.deleteAll();}
重启服务,通过swagger接口文档测试,访问UserController的deleteAll()方法
实现思路
实现步骤:
- 导入Spring Cache和Redis相关maven坐标
- 在启动类上加入@EnableCaching注解,开启缓存注解功能
- 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
- 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解
代码开发
1). 导入Spring Cache和Redis相关maven坐标(已实现)
2). 在启动类上加入@EnableCaching注解,开启缓存注解功能
3). 在用户端接口SetmealController的 list 方法上加入@Cacheable注解

4).在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解:

功能测试
添加购物车
需求分析和设计
产品原型:
接口设计:
• 请求方式:POST• 请求路径:/user/shoppingCart/add• 请求参数:套餐 id 、菜品 id 、口味• 返回结果: code 、 data 、 msg
数据库设计:
• 作用:暂时存放所选商品的地方• 选的什么商品• 每个商品都买了几个• 不同用户的购物车需要区分开用户的购物车数据,也是需要保存在数据库中的,购物车对应的数据表为 shopping_cart 表,具体表结构如下:
说明:
- 购物车数据是关联用户的,在表结构中,我们需要记录,每一个用户的购物车数据是哪些
- 菜品列表展示出来的既有套餐,又有菜品,如果用户选择的是套餐,就保存套餐ID(setmeal_id),如果用户选择的是菜品,就保存菜品ID(dish_id)
- 对同一个菜品/套餐,如果选择多份不需要添加多条记录,增加数量number即可
代码开发
根据添加购物车接口的参数设计DTO:

根据添加购物车接口创建ShoppingCartController:
创建ShoppingCartService接口:
创建ShoppingCartServiceImpl实现类,并实现add方法:
创建ShoppingCartServiceImpl实现类,并实现add方法:
创建ShoppingCartMapper接口:
创建ShoppingCartMapper.xml:
功能测试
查看购物车
需求分析和设计
产品原型:

接口设计:
代码开发
在ShoppingCartController中创建查看购物车的方法:
在ShoppingCartService接口中声明查看购物车的方法:
在ShoppingCartServiceImpl中实现查看购物车的方法:
功能测试
清空购物车
需求分析和设计
产品原型:

接口设计:

代码开发
在ShoppingCartController中创建清空购物车的方法:
在ShoppingCartService接口中声明清空购物车的方法:
在ShoppingCartServiceImpl中实现清空购物车的方法:
在ShoppingCartMapper接口中创建删除购物车数据的方法:
功能测试
上一节:
商品浏览(day06)下-CSDN博客
下一节:
地址簿功能代码(day08上)-CSDN博客
相关文章:
缓存商品、购物车(day07)
缓存菜品 问题说明 问题说明:用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。 结果: 系统响应慢、用户体验差 实现思路 通过Redis来缓存菜品数据,减少数据库查询…...
4【编程语言的鄙视链原因解析】
在编程行业中,是存在鄙视链的,技术越好的圈子越不明显,技术越差的圈子越明显,很多时候为新人营造了错误的观点,我们来针对此类现象为新人们讲解原因 ①心里落差:比如你是学厨师的 你经过过年努力练…...
美团一面面经
第一个问题:介绍一下最近做的项目 第二个问题:我对你项目有个地方比较感兴趣啊。就是你用的那个二级缓存,你的吞吐量有多大啊,为什么需要使用二级缓存? 答: 在二级缓存策略下,笔记详情接口的吞…...
什么是报文的大端和小端,有没有什么记忆口诀?
在计算机科学中,**大端(Big-Endian)和小端(Little-Endian)**是两种不同的字节序(即多字节数据在内存中的存储顺序)。理解这两种字节序对于网络通信、文件格式解析以及跨平台编程等非常重要。 1…...
Spring中BeanFactory和ApplicationContext的区别
目录 一、功能范围 二、Bean的加载时机 三、国际化支持 四、事件发布 五、资源加载 六、使用场景说明 在Spring框架中,BeanFactory和ApplicationContext是两种常见的容器实现方式,它们在功能和使用场景上存在一些显著的差异。本文将详细解析这两种容…...
期货行业专题|基于超融合实现 IT 基础设施现代化与国产化转型实践合集
SmartX 期货行业重要进展 帮助近 60 家期货用户部署 730 超融合节点,含 230 信创节点。 深入 5 大应用场景: 核心生产资源池 主席灾备资源池 信创云资源池 云原生存储与容器资源池 分布式存储资源池 更多超融合金融核心生产业务场景实践…...
AI新玩法:Flux.1图像生成结合内网穿透远程生图的解决方案
文章目录 前言1. 本地部署ComfyUI2. 下载 Flux.1 模型3. 下载CLIP模型4. 下载 VAE 模型5. 演示文生图6. 公网使用 Flux.1 大模型6.1 创建远程连接公网地址 7. 固定远程访问公网地址 前言 在这个AI技术日新月异的时代,图像生成模型已经成为了创意工作者和开发者手中…...
Jenkins-pipeline Jenkinsfile说明
一. 简介: Jenkinsfile 是一个文本文件,通常保存在项目的源代码仓库中,用于定义 Jenkins Pipeline 的行为。使用 Jenkinsfile 可以使 CI/CD 流程版本化,并且易于共享和审核。 二. 关于jenkinsfile: jenkins的pipeline…...
vue3中为什么引入setup,引入setup是为了解决什么问题,setup的执行时机是什么?返回值是什么
在 Vue 3 中,引入 setup 函数是为了提供一种更加简洁、灵活、逻辑分离和可维护的方式来组织组件的逻辑。setup 使得 Vue 3 在构建应用时,能够更加有效地支持组合式 API(Composition API),解决了 Vue 2 中一些组件逻辑组…...
Ubuntu 安装 docker 配置环境及其常用命令
Docker 安装与配置指南 本文介绍如何在 Ubuntu 系统上安装 Docker,解决权限问题,配置 Docker Compose,代理端口转发,容器内部代理问题等并进行相关的优化设置。参考官方文档:Docker 官方安装指南 一、安装 Docker 1…...
自动化01
测试用例的万能公式:功能测试界面测试性能测试易用性测试安全性测试兼容性测试 自动化的主要目的就是用来进行回归测试 新产品--第一个版本 (具备丰富的功能),将产品的整体进行测试,人工创造一个自动化测试用例,在n个版本的时候…...
音频入门(二):音频数据增强
本文介绍了一些常见的音频数据增强方法,并给出了代码实现。 目录 一、简介 二、代码 1. 安装必要的库 2. 代码 3. 各函数的介绍 4. 使用方法 参考: 一、简介 音频数据增强是机器学习和深度学习领域中用于改善模型性能和泛化能力的技术。 使用数据…...
MySQL管理事务处理
目录 1、事务处理是什么 2、控制事务处理 (1)事务的开始和结束 (2)回滚事务 (3)使用COMMIT (4)使用保留点 (5)结合存储过程的完整事务例子 3、小结 …...
MySQL数值型函数详解
简介 本文主要讲解MySQL数值型函数,包括:ROUND、RAND、ABS、MOD、TRUNCATE、CEIL、CEILING、FLOOR、POW、POWER、SQRT、LOG、LOG2、LOG10、SIGN、PI。 本文所有示例中,双横杠左边为执行的SQL语句,右边为执行语句的返回值。 ROU…...
54.DataGrid数据框图 C#例子 WPF例子
首先是绑定一个属性,属性名称无所谓。到时候看属性设置的啥,可能要改。 <DataGrid ItemsSource"{Binding Index_instance}"/> 然后创建INotifyPropertyChanged的类,并把相关固定的代码粘贴上去。 然后把这个目录类建好&am…...
总结6..
背包问题的解决过程 在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值,同…...
复位信号的同步与释放(同步复位、异步复位、异步复位同步释放)
文章目录 背景前言一、复位信号的同步与释放1.1 同步复位1.1.1 综述1.1.2 优缺点 1.2 recovery time和removal time1.3 异步复位1.3.1 综述1.3.2 优缺点 1.4 同步复位 与 异步复位1.5 异步复位、同步释放1.5.1 总述1.5.2 机理1.5.3 复位网络 二、思考与补充2.1 复…...
Gartner发布2025年网络治理、风险与合规战略路线图
新型网络风险和合规义务,日益成为网络治理、风险与合规实践面临的问题。安全和风险管理领导者可以参考本文,实现从被动、专注于合规的方法到主动、进一步自动化方法的转型。 主要发现 不断变化的监管环境和不断扩大的攻击面,使企业机构难以实…...
基于STM32的智能空气质量监测与净化系统设计
目录 引言系统设计 硬件设计软件设计 系统功能模块 空气质量检测模块自动净化模块数据显示与用户交互模块远程监控与数据上传模块 控制算法 空气质量检测与判断算法净化设备控制算法数据记录与远程反馈算法 代码实现 空气质量检测与显示代码自动净化与调节代码数据上传与远程控…...
人工智能之数学基础:线性代数中的线性相关和线性无关
本文重点 在线性代数的广阔领域中,线性相关与线性无关是两个核心概念,它们对于理解向量空间、矩阵运算、线性方程组以及人工智能等问题具有至关重要的作用。 定义与直观理解 当存在一组不全为0的数x1,x2,...,xn使得上式成立的时候,那么此时我们可以说向量组a1,a2...,an…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...








