springboot高级特性-缓存

本文详细介绍了SpringBoot中使用缓存提升性能的方法,包括@Cacheable、@CachePut和@CacheEvict注解的使用,以及如何配置缓存管理器、缓存键生成策略和缓存过期策略。通过实例展示了缓存的添加、更新和清除操作,以及如何避免缓存与数据库数据不同步的问题。
摘要由CSDN通过智能技术生成

缓存:将相应数据存储起来以避免数据的重复创建、处理和传输,可有效提高性能

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);
     }
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值