前言

缓存原理:CacheManager(缓存管理器)——>Cache缓存组件来实际给缓存中存取数据

默认使用的是ConcurrentMapCacheManager==ConcurrentMapCache;将数据保存在ConcurrentMap中。
实际开发中使用缓存中间件:redis,memcached,ehcache;
以下内容是默认模式:

1.pom加依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-cache</artifactId>
  4. </dependency>

2.在application主程序中开启缓存

就是加这个@EnableCaching

  1. @SpringBootApplication
  2. @EnableCaching
  3. public class CacheApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(CacheApplication.class, args);
  6. }
  7. }

3.@Cacheable添加缓存

在调用底层数据库的方法上加@Cacheable参数对结果进行缓存,一般就是在service层。
运行时机:@Cacheable是先从缓存中根据key查,缓存中没有的话才走方法。

  1. @Cacheable(cacheNames = {"emp"})
  2. public Employee getById(Integer id){
  3. return employeeDao.getEmpId(id);
  4. }

解释:@Cacheable注解就可以对该方法返回的结果进行缓存
常用的一些属性设置:

3.1 cacheNames

或者可以直接写value,指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存

3.2 key

缓存数据使用的key;可以用它来指定。 默认是使用方法参数的值
编写SpEL; #id;参数id的值
#a0 #p0 #root. args[0]
例子:getEmp[2]

  1. @Cacheable(value = {"emp"},key = "#root.methodName+'['+#id+']'")
  2. public Employee getById(Integer id){
  3. return employeeDao.getEmpId(id);
  4. }
  5. }

3.3 keyGenerator

key的生成器;可以自己指定key的生成器的组件id
key/keyGenerator:二选一使用
同样也是例子:getEmp[2] 效果如下(跟上面是一样的)
image.png
写法:

  1. 先写一个配置类 ```java @Configuration public class MyCacheConfig { @Bean(“mykeyGenerator”) public KeyGenerator keyGenerator(){
    1. return new KeyGenerator() {
    2. /**
    3. * 生成目标key
    4. * @param target
    5. * @param method
    6. * @param params
    7. * @return
    8. */
    9. @Override
    10. public Object generate(Object target, Method method, Object... params) {
    11. return method.getName()+"["+ Arrays.asList(params) +"]";
    12. }
    13. };
    }

}

  1. 2. service里引用
  2. ```java
  3. @Cacheable(value = {"emp"},keyGenerator = "mykeyGenerator")
  4. public Employee getById(Integer id){
  5. return employeeDao.getEmpId(id);
  6. }

3.4 condition

指定符合条件的情况下才缓存
例子:condition = “#a0>1” 就是说当一个参数大于1的时候才进行缓存

  1. //这里的#a0也就是#id
  2. @Cacheable(value = {"emp"},keyGenerator = "mykeyGenerator",condition = "#a0>1")
  3. public Employee getById(Integer id){
  4. return employeeDao.getEmpId(id);
  5. }

3.5 unless

否定缓存,可以理解成如果不是这样就进缓存。如果是这样就不进缓存
例子:unless = “#id ==2” 当传过来的id值是2的话就不进缓存。

  1. @Cacheable(value = {"emp"},keyGenerator = "mykeyGenerator",condition = "#a0>1",unless = "#id ==2")
  2. public Employee getById(Integer id){
  3. return employeeDao.getEmpId(id);
  4. }

3.6 sync

是否使用异步模式。默认是false。当使用sync注解的时候,unless就不能用了。

4.@CachePut更新缓存

既调用方法,又更新缓存数据;
修改了数据库的某个数据,同时更新缓存
运行时机:1. 先调用目标方法;2.将目标方法的结果缓存起来。
image.png

  1. @Cacheable(value = {"emp"},key = "#id")
  2. public Employee getById(Integer id){
  3. System.out.println("查询员工");
  4. return employeeDao.getEmpId(id);
  5. }
  6. @CachePut(value = {"emp"},key = "#employee.id")
  7. public Employee updateEmp(Employee employee){
  8. System.out.println("更新员工");
  9. employeeDao.updateEmp(employee);
  10. return employee;
  11. }
  1. @GetMapping("/updateEmp")
  2. public Employee updateEmp(Employee employee){
  3. return employeeService.updateEmp(employee);
  4. }
  5. }

5.@CacheEvict:缓存清除

image.png

  1. @CacheEvict(value = "emp",key = "#id")
  2. public void deleteEmp(Integer id ){
  3. System.out.println("删除员工");
  4. // employeeDao.deleteEmp(id);
  5. }
  1. @GetMapping("/deleteEmp/{id}")
  2. public String delete(@PathVariable("id")Integer id){
  3. employeeService.deleteEmp(id);
  4. return "success";
  5. }

6. @Caching组合缓存规则

例子:根据名字查询员工后,让根据ID和根据email查询的时候也有缓存。

  1. @Caching(
  2. cacheable = {
  3. @Cacheable(value = "emp",key = "#name")
  4. },
  5. put = {
  6. @CachePut(value = "emp",key = "#result.id"),
  7. @CachePut(value = "emp",key = "#result.email")
  8. }
  9. )
  10. public Employee getByName(String name){
  11. return employeeDao.getByName(name);
  12. }
  1. @GetMapping("/getByName/{name}")
  2. public Employee getByName(@PathVariable("name") String name){
  3. return employeeService.getByName(name);
  4. }

7.@CacheConfig抽取缓存的公共配置

例子:service层中有很多缓存名字都是一样的,每个方法上都写一遍的话很麻烦。所以抽取个公共的比较好。

  1. @CacheConfig(cacheNames = "emp")
  2. //加到service类上
  1. @Caching(
  2. cacheable = {
  3. @Cacheable(/*value = "emp",*/key = "#name")
  4. },
  5. put = {
  6. @CachePut(/*value = "emp",*/key = "#result.id"),
  7. @CachePut(/*value = "emp",*/key = "#result.email")
  8. }
  9. )
  10. public Employee getByName(String name){
  11. return employeeDao.getByName(name);
  12. }

有了@CacheConfig,上题中的value = “emp”,就可以直接省略不写。