文章参考尚硅谷springboot视频整理出的笔记,仅用作学习与交流
一、JSR107核心规范
spel表达式
简单使用例子
package com.midea.springboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
/**
* 一、搭建基本环境
* 1、建库
* 2、创建实体类封装
* 3、增和mybatis操作数据库
* 1、配置数据源信息
* 2、使用注解版
* 3、创建mapper、service层、controller
* 二、快速体验缓存
* 1、开启基于注解的缓存
* 2、标注缓存注解即可
*
* @Cacheable 根据方法的请求参数对结果进行缓存
* @CacheEvict 清空缓存
* @CachePut 保证方法被调用,更新缓存
*
*/
@MapperScan("com.midea.springboot.mapper")
@SpringBootApplication
//开启缓存注解标签
@EnableCaching
public class SpringBoot08CacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot08CacheApplication.class, args);
}
}
package com.midea.springboot.mapper;
import com.midea.springboot.bean.Employee;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.stereotype.Service;
@MapperScan
public interface EmployeeMapper {
@Select("select * from employee where id =#{id}")
public Employee getEmpById(Integer id);
@Update("update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} where id=#{id}")
public void updateEmp(Employee employee);
@Delete("delete from employee where id=#{id}")
public void deleteEmpById(Integer id );
@Insert("insert into employee(lastName,email,gender,d_id) values(#{lastName},#{email},#{gender},#{dId})")
void insertUse(Employee employee);
@Select("select * from employee where lastName=#{lastName}")
Employee getEmpByLastName(String lastName);
}
```java
package com.midea.springboot.Service;
import com.midea.springboot.bean.Employee;
import com.midea.springboot.mapper.EmployeeMapper;
import org.apache.ibatis.annotations.Update;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
@Service
//@CacheConfig(cacheNames = "emps") 公共配置,所有该类方法定义缓存规则
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 将方法的运行结果进行缓存,以后再要相同的数据直接从缓存中取
* CacheManager管理多个Cache组件的,对缓存的CURD操作在Cache组件中,每个缓存组件有自己的唯一名字
* Cache几个属性
* cacheNames/values 指定缓存组件的名字,(可以指定多个值)。
* key:缓存数据使用key,默认是使用方法参数的值,可以用spel表达式指定
* KeyGenerator key的生成器; 也可以指定key的生成器的组件id,和key一样,key和keyGenerator二选一
* cacheManager:指定所属的缓存管理器;或者用缓存解析器cacheResolver 两个二选一
* condition:指定符合条件才缓存,例如 condition="#id>0" spel表达式
* unless:否定缓存:,当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
* sync:是否使用同步模式
*
* 原理
* 1、自动配置类:CacheAutoConfigurtion
* 2、缓存的配置类
* 0 = "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
* 1 = "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"
* 2 = "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"
* 3 = "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"
* 4 = "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"
* 5 = "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"
* 6 = "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"
* 7 = "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"
* 8 = "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"
* 9 = "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"
* 其中默认生效的配置类:SimpleCacheConfiguration;,这个类在容器中注册了一个缓存管理器CacheManager:ConcurrentMapCacheManager
* 这个缓存管理器可以获取和创建ConcurrentMapCache类型的缓存组件,该组件的数据用ConcurrentHashMap保存;
* 其他缓存管理器可以通过导入相应的依赖来开启
*
* 运行流程
* 以@cacheable为例
* 1、service方法运行之前:先去查询Cache组件,按照Service方法指定的缓存组件name进行获取;
* (CacheManager先获取对应的缓存,如果第一次获取,那么返回值是none,然后自动创建该组件,放入cacheMap中)
* 2、得到cache后,根据key去cache查找缓存的内容,如果缓存标签中没有指定key的值,key由keyGenerator生成,默认的是simpleKeyGenerator
* 规则如下:
* 如果方法没有参数,key= new SimpleKey();(对象地址)
* 一个参数 key= 参数的值
* 多个参数 key= new SimpleKey(params);
* 也可以自己配置了keyGenerator规则。
* 3、如果没有查到缓存(第一次查询,或者缓存被清除时),就调用目标方法(service),得到结果,
* 将结果放进缓存组件中的map存放
* 如果查到缓存,直接返回结果,不再调用方法
*
*
*
*
* @param id
* @return
*/
//先查询缓存,再判断是否执行方法
@Cacheable(cacheNames ="emps",key = "#id" /*keyGenerator = "myKeyGenerator"*/,condition = "#id>0",unless = "#result==null")
public Employee getEmpById(Integer id ){
System.out.println("查询"+id+"号员工");
return employeeMapper.getEmpById(id);
}
/**
* @CachePut 调用方法的同时更新缓存,属性和cacheable类似
* 当我们修改了数据库的某个数据,同时更新缓存,先运行方法,将结果更新到缓存
* 注意要保证key值与要与cacheable中的key值一样,否则缓存数据会被放到map中新的键值对,不会更新原来的缓存
*
*/
@CachePut(cacheNames = "emps",key = "#result.id") //这是result是方法返回的Employee
public Employee updateEmployee(Employee employee){
System.out.println("员工更新方法");
employeeMapper.updateEmp(employee);
return employee;
}
/**
* @ CacheEvict: 缓存清除
* 通过name指定缓存组件
* 通过key指定键值对,也可以用allEntries=true 删除所有键值对
* 特殊属性
* beforeInvocation 默认值false 是否在方法执行前删除缓存,如果为true,及时方法中出现异常或者错误,也会删除缓存
*/
@CacheEvict(cacheNames = "emps" ,key = "#id")
public void deldeteEmp(Integer id){
System.out.println("deleteEmp:"+id );
//employeeMapper.deleteEmpById(id);
}
/**
* 定义组合缓存规则
* @param lastName
* @return
*/
@Caching(
cacheable = {
@Cacheable(value = "emps",key = "#lastName")
},
put = {
@CachePut(value = "emps",key = "#result.id"),//把缓存放到新的键值对,key是返回的结果id,而不是lastName
@CachePut(value = "emps",key = "#result.email")
},
evict = {
@CacheEvict(value = "emps",key = "#result.email")
}
)
public Employee getEmpByLastName(String lastName){
return employeeMapper.getEmpByLastName(lastName);
}
}
package com.midea.springboot.controller;
import com.midea.springboot.Service.EmployeeService;
import com.midea.springboot.bean.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/emp/{id}")
public Employee getEmployee(@PathVariable Integer id){
Employee employee= employeeService.getEmpById(id);
return employee;
}
@GetMapping("/emp")
public Employee update(Employee employee){
Employee employee1 = employeeService.updateEmployee(employee);
return employee;
}
@GetMapping("/delete/{id}")
public String deleteEmpById(@PathVariable Integer id){
employeeService.deldeteEmp(id);
return "success";
}
@GetMapping("/emp/{lastName")
public Employee getEmpByLastName(@PathVariable String lastName){
return employeeService.getEmpByLastName(lastName);
}
}
自定义key的生成策略
package com.midea.springboot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
*
*/
@Configuration
public class MyCacheConfig {
/**
* 加入容器后,还要在目标方法的缓存标签指定使用这个生成器
* @return
*/
@Bean("myKeyGenerator")
public org.springframework.cache.interceptor.KeyGenerator keyGenerator(){
return new org.springframework.cache.interceptor.KeyGenerator(){
@Override
public Object generate(Object target, Method method, Object... params) {
return method.getName()+"["+Arrays.asList(params).toString() +"]";
}
};
}
}