springboot高级特性-缓存
Posted 暴躁的程序猿啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot高级特性-缓存相关的知识,希望对你有一定的参考价值。
缓存:将相应数据存储起来以避免数据的重复创建、处理和传输,可有效提高性能
springboot中使用缓存 可以缓存方法的返回值 等等 避免多次查询数据库
springboot的缓存有以下层级关系
CachingProvider 缓存提供者 —>管理和控制多个CacheManager---->管理和控制多个唯一命名的cache----->存储在cache中的key-value对-------->Expiry 每一个存储在cache中的条目有一个有效期
Spring缓存抽象
cache 定义各种操作
CacheManager 缓存管理器,管理各种缓存组件
Cache缓存接口 定义缓存操作 如:RedisCache。EhCacheCaceh等
缓存注解
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@CacheEvict 清空缓存
@CachePut 保证方法被调用,又希望结果被缓存
@EnableCaching 开启基于注解的缓存
keyGenerator 缓存数据时key生成策略
serialize 缓存数据时value序列化策略
我们要想使用缓存 导入缓存依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
创建一个可以访问数据库的工程
pojo类
/**
* @create: 2021/9/4
* @author: Tony Stark
*/
@Data
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender; //性别 1男 0女
}
定义mapper
@Mapper
public interface EmployeeMapper {
@Select("select * from employee where id =#{id}")
public Employee getEmpById(Integer id);
}
service
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
public Employee getEmp(Integer id){
System.out.println("查询"+id+"号员工");
Employee empById = employeeMapper.getEmpById(id);
return empById;
}
}
controller
@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/emp/{id}")
public Employee getEmployee(@PathVariable("id")Integer id){
Employee emp = employeeService.getEmp(id);
return emp;
}
}
如果我们要使用缓存需要在启动类上加EnableCaching注解开启缓存
@SpringBootApplication
@EnableCaching
public class Springboot01CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01CacheApplication.class, args);
}
}
将方法的运行结果进行缓存;以后再有相同的数据,直接从缓存中取,不用去调方法;
在方法上加上cacheable注解缓存结果
@Cacheable(cacheNames = “emp”)
@Cacheable(cacheNames = "emp")
public Employee getEmp(Integer id){
System.out.println("查询"+id+"号员工");
Employee empById = employeeMapper.getEmpById(id);
return empById;
}
访问测试
http://localhost:8080/emp/1
第一次访问
我们清空控制台进行 第二次访问
可以看到并没有查询数据库 而是使用了缓存 大家可以多试几次
方法的属性 :
**cacheNames/value 😗*指定缓存的名字;将方法的返回结果放在哪个缓存中,是数组的方式可以指定多个缓存
cacheManager管理多个cache组件的,对缓存的真正CRUD操作在cache组件中,每一个缓存有自己唯一一个名字
key: 缓存数据时的key;可以用它来指定 默认使用方法参数的值 值就是方法的返回值
#id 代表取出取出参数id的值作为key
例如 参数传入进来 1 存储为 1-返回值
编写SpEL:#id 参数id的值 #a0 #p0 #root.args[0]
KeyGenerator: key的生成器 : 可以指定key的生成器的组件id
key/KeyGenerator二选一使用
cacheManager:指定缓存管理器 或者cacheResolver指定缓存解析器
condition: 指定符合条件的情况下才缓存
condition = “#id>0” 指定id大于0的时候才进行缓存
@Cacheable(cacheNames = "emp",condition = "#id>2")
public Employee getEmp(Integer id){
System.out.println("查询"+id+"号员工");
Employee empById = employeeMapper.getEmpById(id);
return empById;
}
我现在指定的id>2时才进行缓存
测试一下
第一次访问
第二次访问 可以看出并没有进行缓存
unless: 否定缓存; 当unless指定的条件为true方法的返回值就不回被缓存;可以获取到结果进行判断
unless = “#result == null” 当结果为空时就不进行缓存
sync: 是否使用异步模式 注意开启异步 unless就会失效
@CachePut 注解
加入mapper方法
@Update("update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId}where id=#{id}")
public void updateEmp(Employee employee);
@CachePut : 即调用方法又更新缓存数据
修改了数据库的某个数据,同时更新缓存
运行时机:先调用目标方法把方法的返回值缓存起来
@CachePut(cacheNames = "emp")
public Employee updateEmployee(Employee employee){
employeeMapper.updateEmp(employee);
return employee;
}
测试步骤
先查询一个员工 查到的结果会放到缓存中
http://localhost:8080/emp/1
以后查询的结果还是之前缓存的结果
这时候我们更新这个员工
http://localhost:8080/get?id=1&lastName=&email=王五2858458@qq.com&dId=1&gender=1
更新方法将方法的返回值也放在了缓存中
当我们再次查询这个员工的时候 数据是更新之后的 还是更新之前的值
http://localhost:8080/emp/1
这是为什么呢 难道我们的@CachePut注解没生效??
其实不是的
我们缓存的时候key默认为方法的参数 我们查询的参数为 id 所以缓存key为id id-value
我们更新的方法参数为employee 所以缓存key为employee employee-value
跟我们查询的时候不是一个缓存 所以导致结果没更新 我们需要指定key为同一个可以即可
@CachePut(cacheNames = "emp",key = "#employee.id")
public Employee updateEmployee(Employee employee){
employeeMapper.updateEmp(employee);
return employee;
}
或者
因为我们的 @CachePut注解 是方法返回结果后缓存所以我们可以从方法的返回值中获取
@CachePut(cacheNames = "emp",key = "#result.id")
public Employee updateEmployee(Employee employee){
employeeMapper.updateEmp(employee);
return employee;
}
当然我们的@Cacheable注解是不能用result的 因为我们的@Cacheable注解要在目标方法执行之前按照key去查询缓存 所以没有方法返回的result的结果
这时候我们重新测试
http://localhost:8080/emp/1
我们更新
http://localhost:8080/get?id=1&lastName=wangwu&email=2858458@qq.com&dId=1&gender=1
这时候我们再查询看看会不会更新
答案是已经更新了 且还是缓存中的值没有查询数据库
@CacheEvict注解
@CacheEvict : 缓存清除
通过可以指定要清除的数据 不写默认是参数为key
key = "#id"取出id为key的缓存
参数:allEntries = true 是指定是否删除缓存中的所有数据默认为false true时就是删除缓存中所有数据
beforeInvocation = true 缓存的清除是否在方法之前执行
默认值为true代表在方法执行之后执行 这里需要注意的是 如果是在方法执行之后执行 如果方法抛出了异常 缓存就不会清空。
添加删除的方法
@GetMapping("/deleteEmp/{id}")
public String deleteEmp(@PathVariable("id") Integer id){
employeeService.deleteEmp(id);
return "删除成功";
}
public void deleteEmp(Integer id){
System.out.println("删除员工"+id);
employeeMapper.deleteEmpById(id);
}
添加注解
@CacheEvict(value = "emp",key = "#id" )
public void deleteEmp(Integer id){
System.out.println("删除员工"+id);
employeeMapper.deleteEmpById(id);
}
测试
我们先拿缓存
这是调用删除缓存方法
http://localhost:8080/deleteEmp/1
我们再次查询数据 发现我们的数据是从数据库中拿的不是缓存
@CacheConfig注解
@CacheConfig(cacheNames = “emp”)
可以指定全局的配置 标注在类上该类的所有公共注解只需在类上配置一次即可
@CacheConfig(cacheNames = "emp")
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
@Cacheable(condition = "#id>0")
public Employee getEmp(Integer id){
System.out.println("查询"+id+"号员工");
Employee empById = employeeMapper.getEmpById(id);
return empById;
}
/**
* @CachePut : 即调用方法又更新缓存数据
* 修改了数据库的某个数据,同时更新缓存
* 运行时机:先调用目标方法把方法的返回值缓存起来
* key = "#result.id"
*/
@CachePut(key = "#employee.id")
public Employee updateEmployee(Employee employee){
employeeMapper.updateEmp(employee);
return employee;
}
@CacheEvict(key = "#id",beforeInvocation = true)
public void deleteEmp(Integer id){
employeeMapper.deleteEmpById(id);
}
}
以上是关于springboot高级特性-缓存的主要内容,如果未能解决你的问题,请参考以下文章