瑞吉外卖优化01-缓存优化
本笔记源自黑马程序员的视频课程——《瑞吉外卖》,总结了课程笔记、相关知识点以及可能遇到的问题解决方案,并且增加了课程中未实现的功能,供读者参考。笔记全面且条理清晰,希望帮助读者学习和理解这个外卖项目。
本项目全部笔记见:外卖项目笔记合集
问题:用户数量多,系统访问量大。频繁访问数据库,系统性能下降,用户体验差。解决方法:使用缓存。用户点链接后,服务端先看缓存中有没有相应数据。如果有数据,不用再查数据库。
1. 使用git管理代码
在gitee上新建仓库,名称和当前项目名相同,权限为私有仓库。
1.1 将本地代码推送到仓库
复制远程仓库链接。
打开IDEA,在菜单选中VCS,选择Import into version control,选择create git repository,选中项目。
.gitignore文件中,排除一些文件(除了IDEA自动生成的,还添加了以下的)
1
2
3
4
5
6
7
8.git
logs
rebel.xml
target/
!.mvn/wrapper/maven-wrapper.jar
log.path_IS_UNDEFINED
.DS_Store
offline_user.md右键项目,点击Git,点击Add。
点击IDEA上方工具的Commit,可以加入注释“加入redis,缓存验证码和菜品”,点击Commit and Push
push时,点击Define remote,将刚才复制的远程仓库链接粘到url中,配置远程仓库。
1.2 创建新的分支,把缓存相关优化都放在新的分支上
点击IDEA右下角的分支,新建分支命名为v1.0。
将v1.0分支也推送到远程仓库,当前代码没有改,直接点工具中的Push即可。
2. 环境搭建
2.1 maven坐标
在项目的pom. xml文件中,导入spring data redis的maven坐标:
1 | <!--导入Redis依赖--> |
2.2 配置文件
在项目的application.yml中加入redis相关配置:
1 | spring: |
2.3 配置类
在config包下创建RedisConfig配置类,复制即可。
1 |
|
以上操作完成后,可以Add、Commit、push到远程仓库,附上Commit Message:“Redis环境配置”。
3. 缓存短信验证码
3.1 实现思路
前面我们已经实现了移动端手机验证码登录,随机生成的验证码我们是保存在HttpSession中的(有效期30分钟)。
现在需要改造为:将验证码缓存在Redis中(有效期设置为5分钟),具体的实现思路如下:
- 在服务端UserController中注入RedisTemplate对象,用于操作Redis
- 在服务端UserController的sendMsg方法中,将随机生成的验证码缓存到Redis中,并设置有效期为5分钟
- 在服务端UserController的login方法中,从Redis中获取缓存的验证码,如果登录成功则删除Redis中的验证码
3.2 代码改造
1、在服务端UserController中注入RedisTemplate对象,用于操作Redis
1 |
|
2、在服务端UserController的sendMsg方法中,将随机生成的验证码缓存到Redis中,并设置有效期为5分钟
1 | // session.setAttribute(phone, code); |
3、在服务端UserController的login方法中,从Redis中获取缓存的验证码,如果登录成功则删除Redis中的验证码
1 | // 之前:从session中获取 刚才sendMsg()时session中保存的 该手机号对应的验证码 |
4. 缓存菜品数据
4.1 实现思路
前面我们已经实现了移动端菜品查看功能,对应的服务端方法为DishController的list方法,此方法会根据前端提交的查询条件(categoryId和status)进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。
具体的实现思路如下:
1、改造DishController的list方法,先从Redis中获取菜品数据。如果有,则直接返回,无需查询数据库;如果没有,则查询数据库,并将查询到的菜品数据放入Redis。
2、改造DishController的save和update方法,加入清理缓存的逻辑。后台系统新增菜品或更新菜品信息后,清理缓存,用户点击这个分类后,能看到更新后的菜品。
3、(补充功能)由于我们前面自己补充了启售/停售功能和删除菜品功能,所以此处也需要改造DishController的switchStatus和delete方法。在商家后台启售/停售或者删除菜品后,也要清理缓存。
注意事项:在使用缓存过程中,要注意保证数据库中的数据和缓存中的数据一致,如果数据库中的数据发生变化,需要及时清理缓存数据。
4.2 代码改造
1、改造DishController的list方法,先从Redis中获取菜品数据。需要按照分类,分别缓存。
如果有,则直接返回,无需查询数据库;
如果没有,则查询数据库,并将查询到的菜品数据放入Redis。
先在DishController中注入RedisTemplate对象,用于操作Redis:
1 |
|
list方法中添加:
1 | List<DishDto> dishDtoList = null; // 希望从redis缓存获取到的是List<DishDto>类型的菜品数据 |
2、改造DishController的save和update方法。后台系统新增菜品或更新菜品信息后,清理缓存,用户点击这个分类后,能看到更新后的菜品。
在DishController的save和update方法都添加:
1 | //方法一:清理所有菜品缓存数据 |
3、由于我们前面自己补充了启售/停售功能和删除菜品功能,所以此处也需要改造DishController的switchStatus和delete方法。在商家后台启售/停售或者删除菜品后,也要清理缓存。
DishController的switchStatus方法添加清理缓存的功能,该方法完整代码如下:
1 | /** |
DishController的delete方法添加清理缓存的功能,该方法完整代码如下:
1 | /** |
4.3 提交仓库
最后,将代码提交到Git本地仓库并推送到远程仓库。
并且经过测试没有问题之后,可以将v1.0分支合并至主分支。
再切回v1.0分支,继续完成其他代码。
5. Spring Cache
5.1 Spring Cache 介绍
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。
CacheManager是Spring提供的各种缓存技术抽象接口。
针对不同的缓存技术需要实现不同的CacheManager:
5.2 Spring Cache 常用注解
在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存支持即可。
例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。
5.3 Spring Cache 使用方式-使用map
下面是使用map为例演示这几个注解的使用:
1、准备工作:
- 启动类上加@EnableCaching开启缓存注解功能:
- 使用前还需要在Controller类中注入CacheManager对象:
2、@CachePut将方法的返回值放到缓存中:
3、@CacheEvict将一条或名条数据从缓存中删除:
4、@Cacheable在方法执行前Spring先查看缓存中是否有数据,如果有数据,则(不经过方法)直接返回缓存中的数据;若没有数据,再调用方法并将方法返回值放到缓存中。:
5.4 Spring Cache 使用方式-使用Redis作为缓存产品
在Spring Boot项目中使用Spring Cache的操作步骤(使用redis缓存技术);
1、导入maven坐标
spring-boot-starter-data-redis和spring-boot-starter-cache:
1 | <dependency> |
2、配置application.yml
1 | spring: |
3、在启动类上加@EnableCaching注解,开启缓存注解功能
4、在Controller的方法上加@Cacheable、@CacheEvict等注解,进行缓存操作(同5.3中注解的使用方法)
6. 缓存套餐数据
6.1 实现思路
前面我们已经实现了移动端套餐查看功能,对应的服务端方法为SetmealController的list方法。此方法会根据前端提交的查询条件,进行数据库查询操作。
在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。
具体的实现思路如下:
1、导入Spring Cache和Redis相关maven坐标
2、在application.yml中配置缓存数据的过期时间
3、在启动类上加入@EnableCaching注解,开启缓存注解功能
4、在SetmealController的list方法上加@Cacheable注解。
@Cacheable注解可以实现:在方法执行前Spring先查看缓存中是否有数据,如果有数据,则(不经过方法)直接返回缓存中的数据;若没有数据,再调用方法并将方法返回值放到缓存中。
5、在SetmealController的save和delete方法上加@CacheEvict注解
@CacheEvict注解可以实现:将一条或名条数据从缓存中删除。
6.2 代码改造
1、在pom.xml文件中导入maven坐标:
1 | <dependency> |
2、在application.yml中配置缓存数据过期时间:
1 | spring: |
3、在启动类上添加@EnableCaching注解,开启缓存注解功能
1 | // 加上这个注解后,才会扫描@WebFilter注解,使得过滤器生效 |
4、在SetmealController的list方法上加@Cacheable注解,向redis中添加缓存:
1 | //根据查询条件,拼接出key |
5、在SetmealController的save、delete、update、switchStatus等方法上加@CacheEvict注解,清除缓存:
1 |
allEntries = true,则会删除value(setmealCache)对应的所有缓存数据。
注意:要让R实现Serializable接口(序列化),注解才能生效。
1 |
|
6.3 提交仓库
提交:将代码提交到Git本地仓库并推送到远程仓库。
合并:经过测试没有问题之后,可以先切换(checkout)回master分支,再将v1.0分支合并至主分支。