前言
缓存在数据访问过程中具有重要作用,它能够提高访问效率,还能存储临时数据
一、JCache(JSR-107)规范
Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。
1)CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
2)CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
3)Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
4)Entry是一个存储在Cache中的key-value对。
5)Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。
但是JSR-107规范比较麻烦,一般不用
二、Spring缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术; 并支持使用JCache(JSR-107)注解简化我们开发;
• Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
• Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等;
• 每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。
• 使用Spring缓存抽象时我们需要关注以下两点;
1、确定方法需要被缓存以及他们的缓存策略
2、从缓存中读取之前缓存存储的数据
1、准备
1)导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2)全局配置文件
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_cache?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=chen
#开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
#开启日志打印
loggi
3)新建Bean
package com.sxt.springboot.bean;
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender; //性别 1男 0女
private Integer dId;
public Employee() {
super();
}
public Employee(Integer id, String lastName, String email, Integer gender, Integer dId) {
super();
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.dId = dId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Integer getdId() {
return dId;
}
public void setdId(Integer dId) {
this.dId = dId;
}
@Override
public String toString() {
return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", dId="
+ dId + "]";
}
}
4)新建Mapper
@Mapper
public interface EmployeeMapper {
@Select("select * from employee where id=#{id}")
public Employee getEmpById(Integer id);
@Update("update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} where id=#{id}")
public void updateEmp(Employee emp);
@Delete("delete from employee where id={id}")
public void deleteEmpById(Integer id);
@Delete("insert into employee(lastName,email,gender,d_id) values(#{lastName},#{email},#{gender},#{dId})")
public void insertEmp(Employee emp);
@Select("select * from employee where lastName=#{lastName}")
public Employee getEmployeeByLastName(String lastName);
}
@MapperScan("com.sxt.springboot.mapper")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5)新建Controller和Service
@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/emp/{id}")
public Employee getEmp(@PathVariable("id")Integer id){
Employee emp = employeeService.getEmp(id);
return emp;
}
}
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
public Employee getEmp(Integer id){
return employeeMapper.getEmpById(id);
}
}
2、使用
几个重要概念&缓存注解 | |
---|---|
Cache | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
CacheManager | 缓存管理器,管理各种缓存(Cache)组件 |
@Cacheable | 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,以后需要相同数据直接从缓存取出 |
@CacheEvict | 清空缓存 |
@CachePut | 保证方法被调用,又希望结果被缓存。 |
@EnableCaching | 开启基于注解的缓存 |
keyGenerator | 缓存数据时key生成策略 |
serialize | 缓存数据时value序列化策略 |
1 | @Cacheable/@CachePut/@CacheEvict 主要的参数 | 1 |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | 例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | 例如:@Cacheable(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存 | 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
allEntries (@CacheEvict ) | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | 例如:@CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation (@CacheEvict) | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | 例如:@CachEvict(value=”testcache”,beforeInvocation=true) |
首先要开启基于注解的缓存@EnableCaching
@MapperScan("com.sxt.springboot.mapper")
@EnableCaching
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1)@Cacheable
新建Service
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/*
* 能够根据方法的请求参数对其结果进行缓存,以后需要相同数据直接从缓存取出
*几个属性:
* 1.cacheNames/value:指定缓存的名字,可以指定多个
* 2.key:默认按照方法的所有参数进行组合,可以使用spel
* 3.keyGenerator:可以自己指定,和key只能选一个
* 4.cacheManager
* 5.condition:"#a0>0" 第一个参数的值大于1
* 6.unless:除了
* 7.sync:是否使用异步模式
* 执行之前检查缓存有没有这个数据,默认按照参数作为key来查询,如果没有就
* 执行方法且将结果放入缓存
* */
@Cacheable(cacheNames={
"emp"},key = "#root.methodName",condition = "#a0>0",unless = "#a0==2")
public Employee getEmp(Integer id){
return employeeMapper.getEmpById(id);
}
}
Controller测试
@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/emp/{id}")
public Employee getEmp(@PathVariable("id")Integer id){
Employee emp = employeeService.getEmp(id);
return emp;
}
}
也可以自定义keyGenerator
@Configuration
public class MyCacheConfig {
@Bean("myKeyGennerator")
public KeyGenerator keyGenerator(){
return new KeyGenerator(){
@Override
public Object generate(Object o, Method method, Object... objects)