前言:
经过前面linux,redis,git的学习介绍,我们至此进入项目优化阶段
1. 项目问题 1-1
用户数量多,系统访问量大
频繁访问数据库,系统性能下降,用户体验差
2. 环境搭建 1-2
将我们的项目推送远程仓库 1-2
在创建一个新的分支,在次分支上进行项目优化
将v1.0 分支也推送远程仓库
2.1 maven 坐标 1-3
在项目的pom. xml文件中导入spring data redis 的maven坐标:
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在项目的application. yml中加入redis相关配置:
application.yml
spring:
redis:
host: localhost
port: 6379
#password: 123456
database: 0 #操作的是0号数据库
redis序列化器 RedisConfig 1-3
package com.itheima.reggie.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
//redis序列化器 1-3
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
//默认的Key序列化器为:JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
接着添加,提交
推送成功
3. 缓存短信验证码 1-4
3.1 实现思路
前面我们已经实现了移动端手机验证码登录,随机生成的验证码我们是保存在HttpSession中的。现在需要改造为将验证码缓存在Redis中,具体的实现思路如下:
1、在服务端UserController中注入RedisTemplate对象,用于操作Redis
2、在服务端UserController的sendMsg方法中,将随机生成的验证码缓存到Redis中,并设置有效期为5分钟
3、在服务端UserController的login方法中,从Redis中获取缓存的验证码,如果登录成功则删除Redis中的验证码
3.2 代码改造 1-4
UserController
//注入redisTemplate对象 优化1-4
@Autowired
private RedisTemplate redisTemplate;
获取手机验证码 优化 sendMsg 优1-4
//获取手机验证码 优化1-4
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user,HttpSession session){
//获取手机号
String phone = user.getPhone();
if(StringUtils.isNotEmpty(phone)){//手机号不为空
//生成随机的4为验证码
String code = ValidateCodeUtils.generateValidateCode(4).toString();
log.info("code={}",code);
//调用阿里云提供的短信服务AP完成发送短信
//SMSUtils.sendMessage("瑞吉外卖","",phone,code);
//需要将验证码保存到session
//session.setAttribute(phone,code);
//将生成的验证码缓存到Redis中,并且设置有效期为5分钟 优1-4
redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);
return R.success("手机验证码发送成功");
}
return R.error("短信发送失败");
}
移动端用户登录 优化 login 优1-4
/**
* 移动端用户登录 优化 优1-4
* @param map
* @param session
* @return
*/
@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session){
log.info(map.toString());
//获取手机号
String phone = map.get("phone").toString();
//获取验证码
String code = map.get("code").toString();
//从Session中获取保存的验证码
//Object codeInSession = session.getAttribute(phone);
//从redis中获取缓存的验证码 优1-4
Object codeInSession = redisTemplate.opsForValue().get(phone);
//进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
if(codeInSession != null && codeInSession.equals(code)){
//如果能够比对成功,说明登录成功
//判断当前手机号对应的用户是否为新用户,如果是新用户就自动完成注册
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
//构造查询条件,将手机号作为查询条件
queryWrapper.eq(User::getPhone,phone);
User user = userService.getOne(queryWrapper);
if(user == null){
//是新用户就自动完成注册
user = new User();
user.setPhone(phone);
user.setStatus(1);
userService.save(user);
}
//将用户id放入session
session.setAttribute("user",user.getId());
//如果用户登录成功,删除Redis中缓存的验证码 优1-4
redisTemplate.delete(phone);
return R.success(user);
}
return R.error("登录失败");
}
3.3 测试 1-4
运行程序
查看redis
登录成功
再次查看redis
ps 还可以使用redis图形化界面
E:\java\tools\Redis\ziliao\redisclient-win32.x86_64.2.0.jar : Redis图形界面客户端
执行方式: 在这个文件所在的目录cmd, 执行 java -jar redisclient-win32.x86_64.2.0.jar
启动成功后,点击左上角的Server---add
发送验证码,redis里出现手机号
登录成功后手机号被删除
4. 缓存菜品数据 1-5
4.1 实现思路 1-5
前面我们已经实现了移动端菜品查看功能T对应的服务端方法为DishController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。具体的实现思路如下:
1、改造DishController的list方法,先从Redis中获取菜品数据,如果有则直接返回,无需查询数据库;如果没有则查询数据库,并将查询到的菜品数据放入Redis。
2、改造DishController的save和update方法, 加入清理缓存的逻辑
4.2 代码实现 1-6
DishController
//注入redisTemplate对象 优化1-6
@Autowired
private RedisTemplate redisTemplate;
根据菜品分类的id查询菜品改造 优化 list
//根据菜品分类的id查询菜品改造 优化 优1-6
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish){
List<DishDto> dishDtoList = null;
//动态构造key,使用分类的id和售卖状态可以保证唯一性
//dish_1397844391040167938_1
String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();
//先从redis中获取缓存数据
dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);
if(dishDtoList != null){
//如果存在,直接返回,无需查询数据库
return R.success(dishDtoList);
}
//构造查询条件对象
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
//添加条件,查询状态为1的也就是起售的菜品
queryWrapper.eq(Dish::getStatus,1);
//添加排序条件
queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List<Dish> list = dishService.list(queryWrapper);
//遍历list集合
dishDtoList = list.stream().map((item)->{
DishDto dishDto = new DishDto();
//将普通数据赋值进dishDto
BeanUtils.copyProperties(item,dishDto);
//设置菜品分类名
Long categoryId = item.getCategoryId();//分类id
//根据id查询分类对象
Category category = categoryService.getById(categoryId);
if(category != null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
//设置菜品口味
Long id = item.getId();
LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId,id);
List<DishFlavor> dishFlavorList = dishFlavorService.list(dishFlavorLambdaQueryWrapper);
dishDto.setFlavors(dishFlavorList);
return dishDto;
}).collect(Collectors.toList());
//如果不存在,需要查询数据库,将查询到的菜品数据缓存到Redis
//这里解释opsForValue不是村String类型的嘛,为啥可以存list
//opsForValue()是操作String类型数据的方法,但是可以通过一些转
//换操作,将List类型的元素转换为字符串进行存储,比如序列化操作或转换为JSON格式再存储。
//在读取时,我们也需要将其转换为List类型,但是在读取时需要进行一些转换操作,
// 并且这种方式不能很好地支持对List中的元素进行增删改查等操作。因此,在某些情况下,
// 建议使用Redis中专门的List数据结构来存储List类型的数据,以获得更好的性能和支持更多的操作方式。
redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.MINUTES);
return R.success(dishDtoList);
}
4.2.1 测试 1-6
运行登录,果然在redis中发现了菜品缓存
4.3 更改save和update 1-7
修改菜品 优化 update 1-7
更新菜品我们采取,删除redis中所有以dish_开头的key方法,简单粗暴
//修改菜品 优化 优1-7
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
//调用我们自己实现的方法因为DishDto中包含了dish_flavor表
dishService.updateWithFlavor(dishDto);
//清理所有的菜品的缓存数据
Set keys = redisTemplate.keys("dish_*");
redisTemplate.delete(keys);
return R.success("新增菜品成功");
}
测试更新菜品,发现更新前菜品缓存还在,更新某一个菜品后,所有的菜品缓存被删除
我们再采用精确处理的方法,指清理某个特定被更新的菜品缓存
//修改菜品 优化 优1-7
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
//调用我们自己实现的方法因为DishDto中包含了dish_flavor表
dishService.updateWithFlavor(dishDto);
//清理所有的菜品的缓存数据 y1-7
// Set keys = redisTemplate.keys("dish_*");
// redisTemplate.delete(keys);
//清理某个分类下面的菜品缓存数据 y1-7
//思路就在于我们需要知道被更新菜品缓存的key是多少
String key = "dish_" + dishDto.getCategoryId() + "_1";
redisTemplate.delete(key);
return R.success("新增菜品成功");
}
再更新前缓存优4条,更新后剩下3条,说明我们只删除了被更新菜品的缓存
新增菜品 save 优化 y1-7
/**
* 新增菜品 优化 y1-7
* @param dishDto
* @return
*/
@PostMapping
public R save(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
//调用我们自己在DishServiceImpl实现的方法 4-11
//我们在DishServiceImpl业务层中自己实现数据保存(因为涉及两张
// 表操作框架无法为我们提供合适的方法)
dishService.saveWithFlavor(dishDto);
//清理所有的菜品的缓存数据 y1-7
// Set keys = redisTemplate.keys("dish_*");
// redisTemplate.delete(keys);
//清理某个分类下面的菜品缓存数据 y1-7
//思路就在于我们需要知道被更新菜品缓存的key是多少
String key = "dish_" + dishDto.getCategoryId() + "_1";
redisTemplate.delete(key);
return R.success("新增菜品成功");
}
和更新菜品一样的套路,新增前3条,新增后2条
4.4 提交远程 并合并主分支 1-8
提交
合并
切回主分支
点击右下角master
查看代码合并成功,因为出现了我们注释的代码
5. Spring Cache 1-9
5.1 spring cache介绍 1-9
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一-个注解,就能实现缓存功能。
Spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。
CacheManager是Spring提供的各种缓存技术抽象接口。
针对不同的缓存技术需要实现不同的CacheManager:
5.2 spring cahche常用注解 y1-9
在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类.上使用@EnableCaching开启缓存支持即可。
例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。
5.3 spring cache 使用方法 y1-10
项目在E:\java学习\瑞吉外卖\course2\cache_demo
新建数据库
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>cache_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
applicationg.yml
server:
port: 8080
spring:
application:
#应用的名称,可选
name: cache_demo
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cache_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: lzl
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
实体类User
package com.itheima.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private int age;
private String address;
}
持久层接口UserMapper
package com.itheima.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User>{
}
业务层接口 UserService
package com.itheima.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.entity.User;
public interface UserService extends IService<User> {
}
业务层接口实现类 UserServiceImpl
package com.itheima.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.entity.User;
import com.itheima.mapper.UserMapper;
import com.itheima.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
启动类CacheDemoApplication
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 //开启缓存注解的功能 y1-10
public class CacheDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CacheDemoApplication.class,args);
log.info("项目启动成功...");
}
}
控制层 UserController
package com.itheima.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.entity.User;
import com.itheima.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
//y1-10
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private CacheManager cacheManager;
@Autowired
private UserService userService;
}
5.3.1 保存方法 CachePut:将方法返回值放入缓存 y1-10
/**
* CachePut:将方法返回值放入缓存 y1-10
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
*/
@CachePut(value = "userCache",key = "#user.id")
@PostMapping
public User save(User user){
userService.save(user);
return user;
}
使用postman进行测试
数据库插入数据成功
通过debug查看缓存数据查看缓存成功
5.3.2 删除方法 CacheEvict:清理指定缓存 y1-11
/**
* CacheEvict:清理指定缓存 y1-11
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
*/
@CacheEvict(value = "userCache",key = "#p0")
//@CacheEvict(value = "userCache",key = "#root.args[0]")
//@CacheEvict(value = "userCache",key = "#id")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
测试
现在缓存中存入a,b
现在删除a的缓存,但是我们在操作之前先存入c的缓存,以便区分
缓存中只剩b了,成功
5.3.3 更新方法 CacheEvict:清理指定缓存 y1-11
//更新方法 CacheEvict:清理指定缓存 y1-11
//@CacheEvict(value = "userCache",key = "#p0.id")
//@CacheEvict(value = "userCache",key = "#user.id")
//@CacheEvict(value = "userCache",key = "#root.args[0].id")
@CacheEvict(value = "userCache",key = "#result.id")
@PutMapping
public User update(User user){
userService.updateById(user);
return user;
}
测试,我们往缓存中加入d,e,f
指定修改d
数据库更新成功
查看缓存,再没更新之前时三条数据,执行之后剩下两条d缓存被删除
5.3.4 查询方法 Cacheable y1-12
Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
/**
* Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓
* 存数据;若没有数据,调用方法并将方法返回值放到缓存中
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
* condition:条件,满足条件时才缓存数据
* unless:满足条件则不缓存
*/
//这里解释condition = "#result != null",当返回值不为空时才缓存数据,这是为了防止,我们查不到数据
//也被缓存产生垃圾数据的现象
//unless = "#result == null"时当返回值为空时就不缓存,他和condition是正好相反
//@Cacheable(value = "userCache",key = "#id",condition = "#result != null")
@Cacheable(value = "userCache",key = "#id",unless = "#result == null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
User user = userService.getById(id);
return user;
}
测试
第一次查询了数据库,因为缓存中没有数据
第二次再次查询,不走数据库了,直接走了缓存,因为缓存中有了数据
和上述查询一样的原理,不做测试了
//条件查询,如果id不为空就根据id查,如果name不为空就根据name查,都不为空就一起查 y1-12
@Cacheable(value = "userCache",key = "#user.id + '_' + #user.name")
@GetMapping("/list")
public List<User> list(User user){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(user.getId() != null,User::getId,user.getId());
queryWrapper.eq(user.getName() != null,User::getName,user.getName());
List<User> list = userService.list(queryWrapper);
return list;
}
5.4 使用redis缓存 y1-13
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml
server:
port: 8080
spring:
application:
#应用的名称,可选
name: cache_demo
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cache_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: lzl
#加入redis y1-13
redis:
host: localhost
port: 6379
#password: 123456
#操作的是0号数据库
database: 0
cache:
redis:
time-to-live: 1800000 #设置缓存数据的过期时间
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
测试查询方法
@Cacheable(value = "userCache",key = "#id",unless = "#result == null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
User user = userService.getById(id);
return user;
}
测试缓存成功
6. 缓存套餐数据 y1-14
6.1 实现思路
前面我们已经实现了移动端套餐查看功能,对应的服务端方法为SetmealController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。
具体的实现思路如下:
1、导入Spring Cache和Redis相关maven坐标.
2、在application.yml中 配置缓存数据的过期时间
3、在启动类上加入@EnableCaching注解,开启缓存注解功能
4、在SetmealController的list方法上加入@Cacheable注解
5、在SetmealController的save和delete方法.上加入CacheEvict注解
6.2 代码实现 y1-14
导入Spring Cache和Redis相关maven坐标.
pom.xml
<!--redis依赖 y1-3-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring cache依赖 y1-14-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
在application.yml中 配置缓存数据的过期时间 y1-14
application.yml
cache:
redis:
time-to-live: 1800000 #设置缓存数据的过期时间
在启动类上加入@EnableCaching注解,开启缓存注解功能 y1-14
ReggieApplication
package com.itheima.reggie;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//启动类 5
@Slf4j //这个注解是lombok提供的 日志文件
@SpringBootApplication
@ServletComponentScan //目的是让我们定义的过滤器生效
@EnableTransactionManagement //使我们的事务注解起作用 4-10
@EnableCaching //开启spring Cache
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class,args);
log.info("项目启动成功。。。。!!!***~####");
}
}
在SetmealController的list方法上加入@Cacheable注解 y1-14
SetmealController
/**
* 根据条件查询套餐数据优化 y1-14
* @param setmeal
* @return
*/
@Cacheable(value = "setmealCache",key = "#setmeal.categoryId+'_'+#setmeal.status")
@GetMapping("/list")
public R<List<Setmeal>> list(Setmeal setmeal){
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId());
queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus());
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
List<Setmeal> list = setmealService.list(queryWrapper);
return R.success(list);
}
点击套餐,测试报错,是因为我们的返回值是R>而R是我们自己定义的,没有序列化,需要将其继承序列化接口
改造R
再次重启测试
正常展示
查看缓存
在SetmealController的save和delete方法.上加入CacheEvict注解 y1-14
SetmealController
//新增套餐 优化 y1-14
@CacheEvict(value = "setmealCache",allEntries = true)
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){
log.info("套餐信息 {}",setmealDto);
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}
/**
* 删除套餐 优化 y1-14
* @param ids
* @return
*/
//allEntries = true 表示删除setmealCache底下的所有缓存数据
@CacheEvict(value = "setmealCache",allEntries = true)
@DeleteMapping
public R<String> delete(@RequestParam List<Long> ids){
log.info("ids:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
测试再新增之前套餐缓存还在,新增之后就没了
新增的套餐
6.3 提交代码和合并 y1-15
提交
合并 y1-15
切换回master,然后合并
随便找一个修改过的代码,合并成功
标签:缓存,key,org,y1,import,优化,id From: https://blog.51cto.com/u_15784725/6541195