前言:
经过前面linux,redis,git的学习介绍,我们至此进入项目优化阶段
1.项目问题1-1用户数量多,系统访问量大
频繁访问数据库,系统性能下降,用户体验差
2.环境搭建1-2将我们的项目推送远程仓库1-2在创建一个新的分支,在次分支上进行项目优化
将v1.0分支也推送远程仓库
2.1maven坐标1-3在项目的pom.xml文件中导入springdataredis的maven坐标:
pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>
在项目的application.yml中加入redis相关配置:
application.ymlspring: redis: host: localhost port: 6379 #password: 123456 database: 0 #操作的是0号数据库
redis序列化器RedisConfig1-3package 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@Configurationpublic 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-43.1实现思路前面我们已经实现了移动端手机验证码登录,随机生成的验证码我们是保存在HttpSession中的。现在需要改造为将验证码缓存在Redis中,具体的实现思路如下:
1、在服务端UserController中注入RedisTemplate对象,用于操作Redis
2、在服务端UserController的sendMsg方法中,将随机生成的验证码缓存到Redis中,并设置有效期为5分钟
3、在服务端UserController的login方法中,从Redis中获取缓存的验证码,如果登录成功则删除Redis中的验证码
3.2代码改造1-4UserController//注入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-jarredisclient-win32.x86_64.2.0.jar
启动成功后,点击左上角的Server---add
发送验证码,redis里出现手机号
登录成功后手机号被删除
4.缓存菜品数据1-54.1实现思路1-5前面我们已经实现了移动端菜品查看功能T对应的服务端方法为DishController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。具体的实现思路如下:
1、改造DishController的list方法,先从Redis中获取菜品数据,如果有则直接返回,无需查询数据库;如果没有则查询数据库,并将查询到的菜品数据放入Redis。
2、改造DishController的save和update方法,加入清理缓存的逻辑
4.2代码实现1-6DishController//注入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和update1-7修改菜品优化update1-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.SpringCache1-95.1springcache介绍1-9SpringCache是一个框架,实现了基于注解的缓存功能,只需要简单地加一-个注解,就能实现缓存功能。
SpringCache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。
CacheManager是Spring提供的各种缓存技术抽象接口。
针对不同的缓存技术需要实现不同的CacheManager:
5.2springcahche常用注解y1-9在springboot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类.上使用@EnableCaching开启缓存支持即可。
例如,使用Redis作为缓存技术,只需要导入SpringdataRedis的maven坐标即可。
5.3springcache使用方法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.ymlserver: port: 8080spring: 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: lzlmybatis-plus: configuration: #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: ASSIGN_ID
实体类Userpackage com.itheima.entity;import lombok.Data;import java.io.Serializable;@Datapublic class User implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String name; private int age; private String address;}
持久层接口UserMapperpackage com.itheima.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.itheima.entity.User;import org.apache.ibatis.annotations.Mapper;@Mapperpublic interface UserMapper extends BaseMapper<User>{}
业务层接口UserServicepackage com.itheima.service;import com.baomidou.mybatisplus.extension.service.IService;import com.itheima.entity.User;public interface UserService extends IService<User> {}
业务层接口实现类UserServiceImplpackage 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;@Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {}
启动类CacheDemoApplicationpackage 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-10public class CacheDemoApplication { public static void main(String[] args) { SpringApplication.run(CacheDemoApplication.class,args); log.info("项目启动成功..."); }}
控制层UserControllerpackage 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")@Slf4jpublic 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查询方法Cacheabley1-12Cacheable:在方法执行前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-13pom.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.ymlserver: port: 8080spring: 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-146.1实现思路前面我们已经实现了移动端套餐查看功能,对应的服务端方法为SetmealController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频繁查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统的性能。
具体的实现思路如下:
1、导入SpringCache和Redis相关maven坐标.
2、在application.yml中配置缓存数据的过期时间
3、在启动类上加入@EnableCaching注解,开启缓存注解功能
4、在SetmealController的list方法上加入@Cacheable注解
5、在SetmealController的save和delete方法.上加入CacheEvict注解
6.2代码实现y1-14导入SpringCache和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-14application.ymlcache: redis: time-to-live: 1800000 #设置缓存数据的过期时间
在启动类上加入@EnableCaching注解,开启缓存注解功能y1-14ReggieApplicationpackage 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 Cachepublic class ReggieApplication { public static void main(String[] args) { SpringApplication.run(ReggieApplication.class,args); log.info("项目启动成功。。。。!!!***~####"); }}
在SetmealController的list方法上加入@Cacheable注解y1-14SetmealController/** * 根据条件查询套餐数据优化 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-14SetmealController//新增套餐 优化 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,然后合并
随便找一个修改过的代码,合并成功