您现在的位置是:首页 >技术杂谈 >缓存优化----SpringCache网站首页技术杂谈
缓存优化----SpringCache
spring cache
-
spring Cache介绍
spring cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。
cacheManager是spring提供的各种缓存技术抽象接口
针对不同的缓存技术需要实现不同的cacheManager:
CacheManager 描述 EhCacheCacheManager 使用EhCache作为缓存技术 GuavaCacheManager 使用Google的GuavaCache作为缓存技术 RedisCacheManager 使用Redis作为缓存技术 -
spring cache常用注解
注解 说明 @EnableCaching 开启缓存注解功能 @Cacheable 在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中 @CachePut 将方法的返回值放到缓存中 @CacheEvict 将一条或多条数据从缓存中删除 在Springboot项目中,使用缓存技术只需在项目中导入相关的缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存技术支撑即可
例如:使用redis作为缓存技术,只需要导入spring data redis的maven坐标即可
-
spring cache使用方式
在springboot项目中使用springcache的操作步骤(使用redis缓存技术):
-
导入maven坐标
<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
redis: host: 172.17.2.94 port: 6379 password: root@123456 database: 0 cache: redis: time-to-live: 1800000 #设置缓存过期时间,可选
-
- 在启动类上加上
@EnableCaching
注解,开启缓存注解功能 - 在Controller的方法上加入@Cacheable、@CacheEvict等注解,进行缓存操作
userController
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private CacheManager cacheManager;
@Autowired
private UserService userService;
/**
* CachePut:将方法返回值放入缓存
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
*/
@CachePut(value = "userCache",key = "#user.id")
@PostMapping
public User save(User user){
userService.save(user);
return user;
}
/**
* CacheEvict:清理指定缓存
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
*/
@CacheEvict(value = "userCache",key = "#p0")//p0代表第一个参数,id是第一个参数等价
//@CacheEvict(value = "userCache",key = "#root.args[0]")
//@CacheEvict(value = "userCache",key = "#id")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
//@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;
}
/**
* Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
* condition:条件,满足条件时才缓存数据
* unless:满足条件则不缓存
*/
// @Cacheable(value = "userCache",key = "#id",condition = "#result != null")//在源码中不能使用result这个参数,而unless可以使用result
@Cacheable(value = "userCache",key = "#id",unless = "#result == null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
User user = userService.getById(id);
return user;
}
@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;
}
}
pom.cml
<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>
缓存套餐数据
- 实现思路
前面我们已经实现了移动端套餐查看功能,对应的服务端方法为SetmealController的list方法,此方法会根据前端提交的查询条件进行数据库查询操作。在高并发的情况下,频道查询数据库会导致系统性能下降,服务端响应时间增长。现在需要对此方法进行缓存优化,提高系统性能。
具体的实现思路如下:
- 导入springcache和redis相关maven坐标
- 在application.yml中配置缓存数据的过期时间
- 在启动类上加入@EnableCaching注解,开启缓存注解功能
- 在SetmealController的list方法上加入@Cacheable注解
注意:返回值无法序列化 报错: DefaultSerializer requires a Serializable payload but received an object of type [com.itheima.reggie.common.R]
解决:
public class R<T> implements Serializable {//将R进行序列化不然进行SpringCache的时候会报错
报错:RedisCommandExecutionException: ERR wrong number of arguments for 'set' command
原因:redis版本原因,版本太低了,更换一个高点的redis版本就可以解决
- 在SetmealController的save和delete方法上加入CacheEvict注解
- 代码改造
/*
* 删除套餐
* */
@DeleteMapping
@CacheEvict(value = "setmealCache",allEntries = true)//allEntries = true 该代码的意思是清除缓存中所有的数据
public R<String> delete(@RequestParam List<Long> ids){
log.info("ids:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功!!!!");
}
/*
* 用户端套餐展示,根据条件查询套餐数据
* */
@GetMapping("/list")
@Cacheable(value = "setmealCache",key = "#setmeal.categoryId+'_'+#setmeal.status")
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);
}
- 功能测试
问题(报错解决)
报错:RedisCommandExecutionException: ERR wrong number of arguments for 'set' command
原因:redis版本原因,版本太低了,更换一个高点的redis版本就可以解决