Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,大大简化我们在业务中操作缓存的代码。
Spring Cache只是提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheManager是Spring提供的各种缓存技术抽象接口
在SpringCache中提供了很多缓存操作的注解,常见的是以下的几个:
注解 |
说明 |
@EnableCaching |
开启缓存注解功能 |
@Cacheable |
在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中 |
@CachePut |
将方法的返回值放到缓存中 |
@CacheEvict |
将一条或多条数据从缓存中删除 |

其实在我们基本的pom文件中spring-boot-starter-web 下面的 spring-mvc中的 spring-context中有相关依赖,可以使用spring cache 的基础功能,如果使用基本功能就可以不用导入redis坐标
使用的时候只需要添加注解自动装配
@Autowired
private CacheManager cacheManager
然后要在启动类上加入注解
@EnableCaching
集成Redis
在使用上述默认的ConcurrentHashMap做缓存时,服务重启之后,之前缓存的数据就全部丢失了,操作起来并不友好。在项目中使用,我们会选择使用redis来做缓存,主要需要操作以下几步:
1.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文件中
spring:
redis:
host: 192.168.200.200
port: 6379
password: root@123456
database: 0
cache:
redis:
time-to-live: 1800000 #设置缓存过期时间,可选 以毫秒来计算
3.启动类上加入@EnableCaching注解
在使用方法上加上相对应的注解
保存@CachePut(将方法的返回值放到缓存中)
/**
* CachePut:将方法返回值放入缓存
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
*/
@CachePut(value = "dishCache",key="#dishDto.id")
//@CachePut(value = "dishCache",key="#result.id")
@PostMapping
public R<String> save (@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.saveWithFlavor(dishDto);
return R.success("新增菜品成功");
}
此处的value是设置缓存名称,根据你自己的项目中的分类使用自己定义,然后这一类通用,后面的key就是动态的获取了,此处建议比较好记的方法,方法中形参是什么,最好就写什么,此处小编的是dishDto.id 然后保存的话,根据id保存,因为id唯一所以key如此写
key的写法如下:
#user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ;
#user.name: #user指的是方法形参的名称, name指的是user的name属性 ,也就是使用user的name属性作为key ;
#result.id : #result代表方法返回值,该表达式 代表以返回对象的id属性作为key ;
#result.name : #result代表方法返回值,该表达式 代表以返回对象的name属性作为key ;
如果你不知道其他方式怎么写,可以点击CachePut,进入源码

一定要注意前面一定要加上 #
如果第一次进入源码,没有这些注解,注意你的idea右上角,会有提示让你下载,点击下载配置就可以
@CacheEvict注解 (将一条或多条数据从缓存中删除)
/**
* CacheEvict:清理指定缓存
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key ---->支持Spring的表达式语言SPEL
*/
//@CacheEvict(value = "userCache",key = "#p0") //#p0 代表第一个参数
//@CacheEvict(value = "userCache",key = "#root.args[0]") //#root.args[0] 代表第一个参数
@CacheEvict(value = "userCache",key = "#id") //#id 代表变量名为id的参数
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
@CacheEvict注解 (将一条或多条数据从缓存中删除)
update的方法也是需要删除以前的缓存的信息,所有也是用CacheEvict
@PutMapping
//@CacheEvict(value = "dishCache",key="#p0..id")
//@CacheEvict(value = "dishCache",key="#result.id")
//@CacheEvict(value = "dishCache",key="#root.args[0].id")
@CacheEvict(value = "dishCache",key="#dishDto.id")
public R<String> update (@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.updateWithFlavor(dishDto);
return R.success("更新菜品成功");
}
@Cacheable注解 (在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中)
/**
* Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
* value:缓存的名称,每个缓存名称下面可以有多个key
* key:缓存的key
* condition:条件,满足条件时才缓存数据
* unless:满足条件则不缓存
*/
@Cacheable(value = "dishCache",key="#id",unless = "#result==null")
@GetMapping("/{id}")
public R<DishDto> get(@PathVariable Long id){
DishDto dishDto = dishService.getByIdFlavor(id);
return R.success(dishDto);
}
缓存非null值
在@Cacheable注解中,提供了两个属性分别为: condition, unless
condition : 表示满足什么条件, 再进行缓存 ;
unless : 表示满足条件则不缓存 ; 与上述的condition是反向的 ;
在list方法上加注解@Cacheable
在list方法中进行查询时,有两个查询条件,如果传递了id,根据id查询; 如果传递了name, 根据name查询,那么我们缓存的key在设计的时候,就需要既包含id,又包含name。 具体的代码实现如下:
@Cacheable(value = "dishCache",key = "#dish.id + '_' + #dish.name")
@GetMapping("/list")
public List<Dish> list(dish dish){
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getId() != null,Dish::getId,dish.getId());
queryWrapper.eq(dish.getName() != null,Dish::getName,dish.getName());
List<Dish> list = dishService.list(queryWrapper);
return list;
}
这里根据传递过来的具体信息,设计缓存key 中间的'_' 是字符串拼接
好记性不如烂笔头,赶紧去试试吧