Spring Cahe介绍

Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cahce 提供了一层抽象,底层可以切换不同的 cache 实现。具体就是通过CacheManager接口来统一不同的缓存技术。
CacheManager 是 Spring 提供的各种缓存技术抽象接口
针对不同的缓存技术需要实现不同的 CacheManager:

CacheManager 描述
EnCacheCacheManager 使用 EhCache 作为缓存技术
GuavaCacheManager 使用 Google 的 GuavaCache 作为缓存技术
RedisCachemanager 使用 Redis 作为缓存技术

目前使用Redis缓存技术…

Spring Cache注解

注解 说明
@EnableCaching 开启缓存注解功能【使用在Spring Boot启动类上】
@Cacheable 在方法执行前 spring 先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
@CachePut 将方法的返回值放到缓存中
@CacheEvict 将一条或多条数据从缓存中删除

@Cacheable@CachePut@CacheEvict注解是使用在方法上面的。主要有以下的参数可以将要缓存的数据进行过滤和配置。主要参数如下:

参数名称 说明
value 缓存的名称,必须指定最少一个,一个value可以对应多个key
key 缓存的key,按照SpEL表达式编写
condition 缓存的条件,可以为空,使用SpEL编写,返回true或者false,只有为true才进行缓存/清除缓存,在调用方法之前之后都能判断
unless(@Cacheable@CachePut) 用于否决缓存的,不像condition,该表达式只在方法执行之后判断,此时可以拿到返回值result进行判断。条件为true不会缓存,fasle才缓存
allEntries (@CacheEvict) 是否清空所有缓存内容,缺省为false,如果指定为true,则方法调用后将立即清空所有缓存
beforeInvocation (@CacheEvict) 是否在方法执行前就清空,缺省为false,如果指定为true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

将返回值放入缓存的过程中,若没有unless或condition参数,如果返回值为null,也会放入缓存

SpringBoot缓存设置

可以使用redis作为缓存,也可以不使用外部缓存

不用外部缓存

导入maven坐标spring-boot-starter-web即可。

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>

底层默认使用的是private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);可以看出底层是Map。

使用reids作为缓存

在以上的基础上,再导入maven坐标spring-boot-starter-cachespring-boot-starter-data-redis

1
2
3
4
5
6
7
8
<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>

配置Spring Boot的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
redis:
host: localhost
port: 6379
#password: 123456
database: 0
jedis:
pool:
max-active: 8
max-wait: 1ms
max-idle: 4
min-idle: 0
cache:
redis:
time-to-live: 1800000 #设置缓存数据的过期时间【单位ms】

redis和cache的使用场景和区别

  • 存储方式:
    • cache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小 ;
    • redis有部分存在硬盘上,这样能保证数据的持久性,支持数据的持久化。cache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复 。
  • 数据支持类型:Redis和cache都是将数据存放在内存中
    • cache只支持<key,value>型数据,不过cache还可用于缓存其他东西,例如图片、视频等等;
    • Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
  • 可靠性上:
    • Cache不支持数据持久化,断电或重启后数据消失,但其稳定性是有保证的。
    • Redis支持数据持久化和数据恢复,允许单点故障,但是同时也会付出性能的代价。
  • 应用场景:
    • Cache:动态系统中减轻数据库负载,提升性能;做缓存,适合多读少写,大数据量的情况(如人人网大量查询用户信息、好友信息、文章信息等)。
    • Redis:适用于对读写效率要求都很高,数据处理业务复杂和对安全性要求较高的系统(如新浪微博的计数和微博发布部分系统,对数据安全性、读写要求都很高)。

基本使用

首先你需要在启动类上开启缓存注解功能,使用注解@EnableCaching

1
2
3
4
5
6
7
8
9
@Slf4j
@SpringBootApplication
@EnableCaching //开启缓存注解功能
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
log.info("项目启动完成");
}
}

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

@Autowired
private CacheManager cacheManager;

@Autowired
private UserService userService;

@CachePut(value = "userCache",key = "#result.id")//动态key
@PostMapping
/*
增加数据
*/
public User save(User user){
userService.save(user);
return user;
}

@CacheEvict(value = "userCache",key = "#id")
@DeleteMapping("/{id}")
/*
删除数据
*/
public void delete(@PathVariable Long id){
userService.removeById(id);
}

@CacheEvict(value = "userCache",key = "#user.id")
@PutMapping
/*
修改数据
*/
public User update(User user){
userService.updateById(user);
return user;
}

@Cacheable(value = "userCache",key = "#id",condition = "#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",condition = "#result!=null")
@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;
}
}

SpEL表达式

对于参数:key、condition、unless中,除了可以使用字符串进行配置,也可以使用SpEL表达式进行动态的配置

Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”。

表达式语言给静态Java语言增加了动态功能。

SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。

简单使用示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@CacheEvict(value = "userCache",key = "#user.id")  //以参数user的id属性的值作为key
//@CacheEvict(value = "userCache",key = "#root.args[0].id") 以方法的第一个参数的id属性的值作为 key
//@CacheEvict(value = "userCache",key = "#p0.id") 以方法的第一个参数的id属性的值作为 key
//@CacheEvict(value = "userCache",key = "#result.id") 以方法返回值的id属性的值作为 key
//@CacheEvict(value = "userCache",key = "#root.methodName") 以方法名作为 key
@PutMapping
public User update(User user){
userService.updateById(user);
return user;
}

@Cacheable(value = "userCache",key = "#id") //以参数id作为key
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
User user = userService.getById(id);
return user;
}

参考:

Spring学习笔记(三十二)——SpringBoot中cache缓存的介绍和使用_不愿意做鱼的小鲸鱼的博客-CSDN博客_spring-boot-starter-cache

__END__