@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的生成器的组件idkey/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
俺也不懂。。。
key
:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值 1-方法的返回值,编写SpEL; #id;参数id的值 #a0 #p0 #root.args[0],getEmp[2]keyGenerator
:key的生成器;可以自己指定key的生成器的组件idkey/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;
}
比如condition = "#id>2"
:当id>2的时候,才把这个方法加入缓存中
condition = "#a0>1"
:第一个参数的值>1的时候,才加入到缓存中,a0
是指第一个参数
unless = "#a0>1"
:这个就反过来了,当第一个参数>1的时候,不加入缓存
这个注解一般用于更新之前写的。
执行步骤:在运行完方法后,再调用注解。
先把代码补全
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层负责请求和回传值
@CachePut
:既调用方法,又更新缓存数据;同步更新缓存根据源码可以知道,缓存时根据名字(key)来缓存东西的,比如我们查id=1
,那么,这个key就是1
如果@CachePut
里面没写属性key为多少,那么,根据update()
函数,key就是employee
,一个key为1
,一个key为employee
,两个key不一样,没有进行缓存绑定,也修改不了缓存。
@CachePut
,网页上只是显示了,但不会返回到数据库中@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要一样,才能正常操作
先查询
再修改
控制台:
但是数据库:
虽然网页上没显示,但是!!!!!缓存已经改了,数据库也改了,这是事实!!!!!
以后就,同一个东西的,想要再缓存中,查询的@Cacheable(value = {"xxx"})
,更新的就 @CachePut(value = {"xxx"},key = "#result.yyy")
,首先查询的参数是一个对象的属性,那么yyy就是这个对象中的属性也是查询的参数
@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
:指定清除这个缓存中所有的数据,默认为falsebeforeInvocation = false
:缓存的清除是否在方法之后执行?真就在方法之后执行,假就在方法之前执行。,默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除,默认为falsebeforeInvocation = true
: 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除,默认为false@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
这是一个很厉害的东西,百度说可以缓存什么东西的。
可惜,我不会,算了,以后再学,等以后找到工作要用吧。。。太多东西学不完了