Spring Boot从0开始学的个人笔记7 -- 缓存cache

一、概念

  • Cache:缓存接口,定义缓存操作
  • @EnableCaching:开启缓存模式
  • CacheManager:缓存管理器,管理各种缓存组件
  • @Cacheable:用于方法前,一般用于查询某个id的操作方法之前,这样,下次如果再查这个ID,就不执行方法,直接从缓存中拿结果
  • @CacheEvict:清空缓存,一般用于删除某个ID的方法前
  • @CachePut:保证方法被调用,又希望结果被缓存,用于更新的方法之前

二、创建项目

在这里插入图片描述
先做好准备,导入基本的东西
spring-boot-mycache-做好前期准备(中文去掉)
数据库:cache

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `departmentName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `lastName` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `gender` int(2) DEFAULT NULL,
  `dId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  • 注意啊,这里多了一个service层,这个可以理解为Mapper和Controller之间的东西,更加规范化

三、初步使用缓存

EmployeeService:

@Service
public class EmployeeService{
    
    
    @Autowired
    EmployeeMapper employeeMapper;

    @Cacheable(cacheNames = {
    
    "emp"})
    public Employee getEmp(Integer id){
    
    
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }
}

@Cacheable调用方法之前执行。里面的可选属性非常多,下面有几个属性

  • cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
  • key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值 1-方法的返回值,编写SpEL; #id;参数id的值 #a0 #p0 #root.args[0],getEmp[2]
  • keyGenerator:key的生成器;可以自己指定key的生成器的组件id
  • key/keyGenerator:二选一使用;
  • cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
  • condition:指定符合条件的情况下才缓存;比如condition = "#id>0":第一个参数的值>1的时候才进行缓存
  • unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断。比如unless = "#result == null":如果结果为空,则不保存。unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
  • sync:是否使用异步模式

下面是SpEL的格式,就是@Cacheable里面的属性可以写的格式,但是@Cacheable不可以用#result,因为害没用返回结果,@Cacheable是在方法运行前执行的
在这里插入图片描述
还要在SpringBootMycacheApplication类前面加上注解@EnableCaching,开启缓存机制

当我们输入http://localhost:8080/emp/1的时候,控制台
在这里插入图片描述
档你按多几次@EnableCaching的时候,控制台也不会再弹多几次出现,因为已经保存到缓存里面去了,Java会自动调用缓存里面的东西,而不会调用方法

四、简单说下原理

1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator
俺也不懂。。。

五、 属性

1、key/keyGenerator

  • key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值 1-方法的返回值,编写SpEL; #id;参数id的值 #a0 #p0 #root.args[0],getEmp[2]
  • keyGenerator:key的生成器;可以自己指定key的生成器的组件id
  • key/keyGenerator:二选一使用;

比如我们访问的是http://localhost:8080/emp/1,id为1,那么默认的key就是1
但是如果@Cacheable(cacheNames = {"emp"},key = "#root.methodName+'['+#id+']'"),让key为方法名[id],比如id为1,那么该key为getEmp[1](因为我们这个@Cacheable注解是放在方法前面的,key是其中的属性)

keyGenerator这个,写一个类,然后用的,我不会。。。。

    @Cacheable(cacheNames = {
    
    "emp"},key = "#root.methodName+'['+#id+']'")
    public Employee getEmp(Integer id){
    
    
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }

2、condition/unless

比如condition = "#id>2":当id>2的时候,才把这个方法加入缓存中
condition = "#a0>1":第一个参数的值>1的时候,才加入到缓存中,a0是指第一个参数
unless = "#a0>1":这个就反过来了,当第一个参数>1的时候,不加入缓存

六、@CachePut

这个注解一般用于更新之前写的。
执行步骤:在运行完方法后,再调用注解。

先把代码补全
EmployeeService:

//这一行是正确的写法,如果没有的话,就产生下面说的key不一致的错误
@CachePut(/*value = "emp",*/key = "#result.id")
public Employee updateEmp(Employee employee){
    
    
    System.out.println("updateEmp:"+employee);
    employeeMapper.updateEmp(employee);
    return employee;
}

EmployeeController:

@GetMapping("/emp")
public Employee update(Employee employee){
    
    
    Employee emp = employeeService.updateEmp(employee);
    return emp;
}

也是service调用Mapper层的东西,然后controller层负责请求和回传值

1、解析

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

根据源码可以知道,缓存时根据名字(key)来缓存东西的,比如我们查id=1,那么,这个key就是1
如果@CachePut里面没写属性key为多少,那么,根据update()函数,key就是employee,一个key为1,一个key为employee,两个key不一样,没有进行缓存绑定,也修改不了缓存。
在这里插入图片描述

  • 就是因为key不一样,或者更新的时候,没有用到@CachePut,网页上只是显示了,但不会返回到数据库中

2、正确的更新缓存写法:

@CachePut里面加上属性key = "#result.id"或者key = "#employee.id",那么,就不会使用默认key为参数,而是变成了#result.id或者#employee.id。前者的意思是key为该方法的结果的id,因为返回结果是employee,属性为id,比如我们跟新的id是1,那么这个key也变成了1而不是employee,后者的结果和前面一样。
注意把上面的key = "#root.methodName+'['+#id+']'"删除了,否则id不一样实验不了

    @Cacheable(value = {
    
    "emp"})
    public Employee getEmp(Integer id){
    
    
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }
    @CachePut(value = {
    
    "emp"},key = "#result.id")
    public Employee updateEmp(Employee employee){
    
    
        System.out.println(employee.getdId());
        System.out.println("updateEmp:"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }

这两个,操作的缓存名字都叫emp,然后呢,在emp里面,两个的key要一样,才能正常操作
先查询
在这里插入图片描述
再修改
在这里插入图片描述
控制台:
在这里插入图片描述
但是数据库:
在这里插入图片描述
虽然网页上没显示,但是!!!!!缓存已经改了,数据库也改了,这是事实!!!!!

3、以后就这么使用

以后就,同一个东西的,想要再缓存中,查询的@Cacheable(value = {"xxx"}),更新的就 @CachePut(value = {"xxx"},key = "#result.yyy"),首先查询的参数是一个对象的属性,那么yyy就是这个对象中的属性也是查询的参数

七、@CacheEvict:缓存清除

@CacheEvict:缓存清除
service层

    @CacheEvict(value="emp"/*beforeInvocation = true*/,key = "#id")
    public void deleteEmp(Integer id){
    
    
        System.out.println("deleteEmp:"+id);
        employeeMapper.deleteEmpById(id);
    }

EmployeeController:

    @GetMapping("/delemp")
    public String deleteEmp(Integer id){
    
    
        employeeService.deleteEmp(id);
        return "成功删除"+id+"号员工";
    }

@CacheEvict中的属性:

  • key:指定要清除的数据
  • allEntries = true:指定清除这个缓存中所有的数据,默认为false
  • beforeInvocation = false:缓存的清除是否在方法之后执行?真就在方法之后执行,假就在方法之前执行。,默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除,默认为false
  • beforeInvocation = true: 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除,默认为false


在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
再查
在这里插入图片描述
在这里插入图片描述

  • 这里再次显示在控制台,是因为那个删除,都把缓存删除了,没有缓存了,再查的时候只能调用方法,调用数据库了。如果这个时候再查,就是调用缓存的了

八、@Caching和@CacheConfig

@Caching的源码:

public @interface Caching {
    
    
    Cacheable[] cacheable() default {
    
    };

    CachePut[] put() default {
    
    };

    CacheEvict[] evict() default {
    
    };
}

这是一个复杂组合的缓存机制,可以写成

// @Caching 定义复杂的缓存规则
@Caching(
        cacheable = {
    
    
                @Cacheable(value="emp",key = "#lastName")
        },
        put = {
    
    
                @CachePut(value="emp",key = "#result.id"),
                @CachePut(value="emp",key = "#result.email")
        }
)
public Employee getEmpByLastName(String lastName){
    
    
    return employeeMapper.getEmpByLastName(lastName);
}
  • 就是,这个一个注解,就用了那么多个缓存的注解(其实也可以分开一个个用)

@CacheConfig://抽取缓存的公共配置
比如@CacheConfig(cacheNames="emp"),用在类前面,就说明了这个类的所有缓存value或者cacheNames都是emp

九、redis

这是一个很厉害的东西,百度说可以缓存什么东西的。
可惜,我不会,算了,以后再学,等以后找到工作要用吧。。。太多东西学不完了

猜你喜欢

转载自blog.csdn.net/yi742891270/article/details/107728606