java中Cache缓存
1.JSR107
缓存的整体架构:
2.SpringBoot的缓存抽象
几个重要概念以及缓存注解
其中想要使用缓存直接,就必须开启**@EnableCaching**注解
开启缓存注解的步骤:
作为Spring框架的核心功能之缓存注解,该功能也继承了Spring这个优良特性,使它生效只需要轻松两步:
1.配置类上开启缓存注解支持:@EnableCaching
2.向容器内至少放置一个CacheManager类型的Bean
这样就可以开工使用Spring强大的缓存注解功能了。
@EnableCaching
@Configuration
public class CacheConfig {
@Bean
public ConcurrentMapCacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
//cacheManager.setStoreByValue(true); //true表示缓存一份副本,否则缓存引用
return cacheManager;
}
}
@Cacheable
@Cacheable //对方法结果能够放入缓存中,比如若根据id查找user时,会将返回的结果放进换缓存中,如果下一次再进行相同操作,便不会调用方法,而是直接从缓存中获取结果值
public User getUser(Integer id);
@CacheEvict:能够清空缓存
@CachePut
@CachePut //能够更新缓存的值,加上这个注解每次更新缓存的时候都会调用这个方法,然后将更新的结果返回到缓存中
public User updateUser(User user);
实例:
@CacheConfig(cacheNames = "emp") //抽取缓存的公共配置
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/*
* 将方法的运行结果进行缓存,以后再要相同的数据就直接从缓存取,不用再次调用这个方法
* CacheManager管理多个cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一的名字
* 几个属性:
* cacheName/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
* key:缓存数据使用的key;可以用它来指定,若果不指定,默认使用方法参数的值(比如id传入1:则 key-value为 1-方法的返回值)
* 编写SqEL:#id:参数id的值 #a0 #p0 #root.args[0] 这几个效果都是一样的,取出第一个参数,作为key
* key = "#id"
* keyGenerator:key的生成器;可以自己指定key的生成器的组件id
* key/keyGenerator二选一使用
* CacheManager:指定缓存管理器 或者使用CacheResolver缓存解析器
* condition:指定符合条件的情况下才缓存;
* condition = "#id>0"
* unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存,可以获取到结果进行判断
* unless = "#result==null"
* sync:是否使用异步模式
*原理:
* 1.自动配置类:CacheAutoConfiguration
* 2.缓存的配置类
* 。。。。。。
* 3.哪个配置类默认生效:SimpleCacheConfiguration
* 4.给容器中注册了一个CacheManager:ConcurrentMapCacheManager
* 5.可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中
*
* 运行的流程:
* @Cacheable:
* 1.方法运行之前,先去插叙Cache(缓存组件),按照cacheNames指定的名字获取;
* (CacheManager先获取相应的缓存),第一次获取缓存如果没有找到指定的Cache组件,会自动创建出来
* 2.去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
* key是按照某种策略生成的;默认是使用KeyGenerator生成的,默认使用SimpleKeyGenerator生成key
* SimpleKeyGenerator生成策略:
* 如果方法没有参数,key=new SimpleKey()
* 方法有一个参数,key=参数的值
* 方法有多个参数,key=new SimpleKey(params)
* 3.没有查到缓存就调用目标方法;
* 4.将目标方法返回到结果,放进缓存中
*
* @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,如果有,就从缓存中获取不会调用方法,
* 如果没有,就调用这个方法并将方法结果放到缓存中,以后再来调用就可以直接使用缓存中的数据。
*
* 核心:
* 1)、使用CacheManager【默认:ConcurrentMapCacheManager】按照名字得到Cache【默认:ConcurrentMapCache】组件
* 2)、key使用KeyGenerator生成的,默认是SimpleKeyGenerator
* */
@Cacheable(cacheNames = "emp"/*, keyGenerator = "myKeyGenerator"*/)
public Employee getEmp(Integer id) {
System.out.println("查询" + id + "号员工");
Employee emp = employeeMapper.getEmployeeById(id);
return emp;
}
@Cacheable(/*cacheNames = "emp",*/key = "#employee.id")
public Employee insertEmp(Employee employee){
System.out.println("InsertEmp:"+employee.getId());
employeeMapper.insertEmployee(employee);
return employee;
}
/*
* @CachePut:既调用方法,又更新缓存数据;同步更新缓存
* 修改了数据库的某个数据,同时更新缓存;
* 运行时机:
* 1、先调用目标方法
* 2、将目标方法的结果缓存起立
*
* 测试步骤:
* 1、查询1号员工;查到的结果会放到缓存中
* 2、以后查询还是之前的结果
* 3、更新1号员工:【lastName=zhangsan; gender=0】
* 将方法的返回值也放进了缓存:
* key:传入的对象 值:返回的employee对象;
* 4、查询1号员工?
* */
@CachePut(/*value = "emp",*/ key = "#result.id")
public Employee updataEmp(Employee employee) {
System.out.println("updateEmp:" + employee);
employeeMapper.updataEmployee(employee);
return employee;
}
/*
* @CacheEvict:缓存清除
* key:指定要清除的数据
* allEntries=true:默认为false,设置为true,当删除缓存数据时,便会删除指定缓存中的所有数据
* beforeInvocation(布尔型):缓存的清除是否在方法之前执行
* false(默认值):代表在方法执行之后执行;如果该方法运行时出现异常缓存就不会清除
* true:代表在方法执行之前执行;如果该方法运行时出现异常,缓存也会被清除
* */
@CacheEvict(/*value = "emp",*/key = "#id")
public void deleteEmp(Integer id){
System.out.println("deleteEmp:"+id);
// employeeMapper.deleteEmployeeById(id);
}
//@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);
}
}