java中Cache缓存
1.JSR107
缓存的整体架构:
2.SpringBoot的缓存抽象
几个重要概念以及缓存注解
其中想要使用缓存直接,就必须开启**@EnableCaching**注解
开启缓存注解的步骤:
作为Spring框架的核心功能之缓存注解,该功能也继承了Spring这个优良特性,使它生效只需要轻松两步:
1.配置类上开启缓存注解支持:@EnableCaching
2.向容器内至少放置一个CacheManager类型的Bean
这样就可以开工使用Spring强大的缓存注解功能了。
@EnableCaching
@Configuration
public class CacheConfig {@Beanpublic 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 {@AutowiredEmployeeMapper 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);}
}