缓存商品、购物车(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的写法如下

  1. #user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ;
  2. #result.id : #result代表方法返回值,该表达式 代表以返回对象的id属性作为key ;
  3. #p0.id:#p0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
  4. #a0.id:#a0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
  5. #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()方法

实现思路

实现步骤:

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

代码开发

1). 导入Spring Cache和Redis相关maven坐标(已实现)

2). 在启动类上加入@EnableCaching注解,开启缓存注解功能

3). 在用户端接口SetmealController的 list 方法上加入@Cacheable注解

4).管理端接口SetmealControllersavedeleteupdatestartOrStop等方法上加入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博客

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

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

相关文章

C++ 在2D与3D游戏的开发库

在当今的游戏开发领域,C++以其高效性、灵活性和强大的性能成为众多开发者首选的语言之一。 C++游戏库流行程度排行榜单 Unreal Engine - 因其全面的功能集和易用性成为最受欢迎的3D引擎之一。Cocos2d-x - 在移动2D游戏开发领域占据重要位置,因其高效性能和易用性而备受推崇…

K8S中Service详解(三)

HeadLiness类型的Service 在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,…

npm install 报错:Command failed: git checkout 2.2.0-c

[TOC](npm install 报错:Command failed: git checkout 2.2.0-c) npm install 报错:Command failed: git checkout 2.2.0-c export NODE_HOME/usr/local/node-v14.14.0-linux-x64 npm config set registry https://registry.npmmirror.com 使用如上环…

DDD - 微服务落地的技术实践

文章目录 Pre概述如何发挥微服务的优势怎样提供微服务接口原则微服务的拆分与防腐层的设计 去中心化的数据管理数据关联查询的难题Case 1Case 2Case 3 总结 Pre DDD - 软件退化原因及案例分析 DDD - 如何运用 DDD 进行软件设计 DDD - 如何运用 DDD 进行数据库设计 DDD - 服…

【Leetcode 热题 100】763. 划分字母区间

问题背景 给你一个字符串 s s s。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s s s。 返回一个表示每个字符串片段的长度的…

ChatGPT是强人工智能吗?

ChatGPT是强人工智能吗? 本文从人工智能发展的三个阶段的角度,分析当前强大的AI大模型所处的阶段,并通过对比各阶段的定义,明确各阶段的特点和未来发展方向; Narrow AI(弱人工智能)、AGI(人工通用智能)和 ASI(人工超级…

通过视觉语言模型蒸馏进行 3D 形状零件分割

大家读完觉得有帮助记得关注和点赞!!!对应英文要求比较高,特此说明! Abstract This paper proposes a cross-modal distillation framework, PartDistill, which transfers 2D knowledge from vision-language models …

深入探索 Nginx 的高级用法:解锁 Web 服务器的强大潜能

在当下互联网技术飞速发展的浪潮中,Nginx 凭借其轻量级、高性能的特性,在 Web 服务器和反向代理服务器领域脱颖而出,成为众多开发者和运维工程师的得力工具。它不仅能高效处理静态资源,在负载均衡、反向代理等方面也表现出色。然而…

【大模型】ChatGPT 高效处理图片技巧使用详解

目录 一、前言 二、ChatGPT 4 图片处理介绍 2.1 ChatGPT 4 图片处理概述 2.1.1 图像识别与分类 2.1.2 图像搜索 2.1.3 图像生成 2.1.4 多模态理解 2.1.5 细粒度图像识别 2.1.6 生成式图像任务处理 2.1.7 图像与文本互动 2.2 ChatGPT 4 图片处理应用场景 三、文生图操…

从零到一:Spring Boot 与 RocketMQ 的完美集成指南

1.Rocket的概念与原理 RocketMQ 是一款由阿里巴巴开源的分布式消息中间件,最初用于支持阿里巴巴的海量业务。它基于发布-订阅模型,具备高吞吐、低延迟、高可用和强一致性的特点,适用于消息队列、大规模数据流处理等场景。以下是对 RocketMQ …

mysql数据库启动出现Plugin ‘FEEDBACK‘ is disabled.问题解决记录

本人出现该问题的环境是xampp,异常关机,再次在xampp控制面板启动mysql出现该问题。出现问题折腾数据库之前,先备份数据,将mysql目录下的data拷贝到其他地方,这很重要。 然后开始折腾。 查资料,会发现很多…

MySQL日期时间函数详解

简介 本文主要讲解MySQL中的日期时间函数,包括:NOW、CURRENT_TIMESTAMP、CURDATE、CURRENT_DATE、CURTIME、CURRENT_TIME、STR_TO_DATE、DATE_FORMAT、TIME_FORMAT、DATE、TIME、YEAR、MONTH、DAY、HOUR、MINUTE、SECOND、QUARTER、YEARWEEK、WEEKDAY、…

ChatGPT 写作系列

ChatGPT 辅助写作 | 专栏 1 写作核心​ 先讲一下 ChatGPT 写作的核心。核心就是需要有文章大纲,而且文章大纲要足够细致。​ 具体怎么做呢?​ 提前准备多级标题大纲,刚开始有两个级别的标题就行,等用熟练了再细化。分一级标题&…

(1)STM32 USB设备开发-基础知识

开篇感谢: 【经验分享】STM32 USB相关知识扫盲 - STM32团队 ST意法半导体中文论坛 单片机学习记录_桃成蹊2.0的博客-CSDN博客 USB_不吃鱼的猫丿的博客-CSDN博客 1、USB鼠标_哔哩哔哩_bilibili usb_冰糖葫的博客-CSDN博客 USB_lqonlylove的博客-CSDN博客 USB …

【Java】Java抛异常到用户界面公共封装

前言 在Java中处理代码运行异常是常见的技术点之一,我们大部分会使用封装的技巧将异常进行格式化输出,方便反馈给用户界面,也是为了代码复用 看看这行代码是怎么处理异常的 CommonExceptionType.SimpleException.throwEx("用户信息不…

mkv转码mp4(ffmpeg工具)

基于windows,Linux也可以用,都是命令行 下载路径(https://github.com/BtbN/FFmpeg-Builds/releases) 下载安装包:ffmpeg-n6.1-latest-win64-lgpl-6.1.zip,(根据自己的平台选择下载)并…

力扣-数组-414 第三大的数

解析 先利用set去重&#xff0c;然后用逆向遍历找到第三大的数 代码 class Solution { public:int thirdMax(vector<int>& nums) {set<int> numsToset;for(int i 0; i<nums.size(); i){numsToset.insert(nums[i]);}int index;if(numsToset.size() > …

没有公网IP实现seafile本地IP访问和虚拟局域网IP同时访问和上传文件

前言 Ubuntu 24.04 LTSDocker 安装 seafileOpenWrtTailscale Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘中&#xff0c;已经实现了本地局域网放问Ubuntu IP来访问Seafile&#xff0c;以及通过 Ubuntu 的 Tailscale IP 访问Seafile。但是&#xff0c;文…

私有IP、VLAN和VPC,分别适合哪些场景你知道吗?

当我们在云中构建应用程序&#xff0c;尤其是使用了第三方云服务商的服务并且我们无法完全掌控后端的每部分时&#xff0c;安全性可能是最需要关注的地方。但这是一项充满挑战的工作&#xff0c;因为保护应用程序的方法实在是太多了&#xff01;为了改善安全性&#xff0c;开发…

【Uniapp-Vue3】setTabBar设置TabBar和下拉刷新API

一、setTabBar设置 uni.setTabBarItem({ index:"需要修改第几个", text:"修改后的文字内容" }) 二、tabBar的隐藏和显式 // 隐藏tabBar uni.hideTabBar(); // 显示tabBar uni.showTabBar(); 三、为tabBar右上角添加文本 uni.setTabBarBadge({ index:"…