这里新增长一个例子:java
`spring
package com.atguigu.cache.service; import com.atguigu.cache.bean.Employee; import com.atguigu.cache.mapper.EmployeeMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.*; import org.springframework.stereotype.Service; @CacheConfig(cacheNames = "emp") [@Service](https://my.oschina.net/service) public class EmployeeService { @Autowired EmployeeMapper employeeMapper; /** * 将方法的运行结果进行缓存,之后在要相同的数据,直接从缓存中获取,不用调用方法 * * CacheManager管理多个Cache组件的,对缓存的真正CRUD操做在Cache组件中,每个缓存 * 组件有本身惟一一个名字 * * 几个属性: * cacheName/value:指定缓存组件的名字;将方法的返回结果放在哪一个缓存中,是数组的方式,能够指定多个缓存; * key:缓存数据使用的key,能够用它来指定,默认是使用方法参数的值 1-方法的返回值 * 编写SqEL; #id,参数id的值 #a0 #p0 #root.args[0] * keyGenerator:key的生成器;能够本身指定key的生成器的组件 * key/keyGenerator:二选一使用 * cacheManager:缓存管理器;或者cacheResolver指定获取解析器 * condition:指定符合条件的状况下才缓存; * condition="#id>0" * condition="#a0>1"l;第一个参数的值>1 的时候才进行缓存 * (a0等于arg[0]) * unless:否认缓存;当unless指定的条件为true,方法的返回值就不会被缓存;能够 * 获取到结果进行判断unless="#a0==2":若是第一参数的值是2,结果不缓存 * sync:是否使用异步模式:异步模式不支持unless * * 原理: * 1.缓存的自动配置类;CacheAutoConfiguration * 2.缓存的配置类 * org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration * org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration * org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration * org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration * org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration * org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration * org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration * org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration * org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】 * org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration * 3.哪一个配置类生效; SimpleCacheConfiguration * * 4.给容器中注册了一个CacheManager、ConcurrentMapCacheManager * 5.能够获取和建立ConcurrentMapCache类型的缓存组件;他的做用将数据保存在ConcurrentMap中; * * 运行流程: * @Cacheable: * 1.方法运行以前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取; * (CacheManager先获取相应的缓存),第一次获取缓存若是没有Cache组件会自动建立, * 2.去Cache中查找缓存的内容,使用一个key,默认就是方法的参数; * key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用 * SimpleKeyGenerator生成key的默认策略; * 若是没有参数;key=new SimpleKey(); * 若是有一个参数,key=参数的值 * 若是有多个参数:key=new SimpleKey(params); * 3.没有查到缓存就调用目标方法; * 4.将目标方法的缓存结果,放进缓存中 * * @Cacheable标注的方法执行以前先来检查缓存中有没有这个数据,默认按照参数的值做为key去查询缓存, * 若是没有就运行方法并将结果放入缓存,之后再来调用就能够直接使用缓存中的数据 * * 核心: * 1)、使用CacheManager【ConcurrentMapCacheManager】按照名字获得Cache【ConcurrentMapCache】组件 * 2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator * @param id * @return */ @Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/) public Employee getEmp(Integer id){ System.out.println("查询"+id+"号员工"); Employee emp=employeeMapper.getEmpById(id); return emp; } /** * @CachePut:即调用方法,又更新缓存数据:同步更新缓存 注意key要相同 * 修改了数据库的某个数据,同时更新缓存; * 运行时机: * 一、先调用目标方法 * 二、将目标方法的结果缓存起来 * * 测试步骤: * 一、查询1号员工;查到的结果会放在缓存中 * key:1 value: lastName:张三 * 二、之后查询仍是以前的结果 * 三、更新1号员工;【LastName:zhangsan:gender:0】 * 将方法的返回值也放进缓存了; * key: 传入的employee对象 值:返回employee对象; * 四、查询1号员工? * 应该是更新后的员工; * key = "#employee.id":使用传入的参数的员工的id; * key = "#result.id";使用返回后的id * @Cacheable的key是不能用#result: * 缘由:由于@Cacheable运行时机有两个,一个是在运行方法以前 * 一个是在运行方法以后,咱们要在方法一开始就获得key,Put * 是先执行方法的,而able是先执行注解的 * 为何是没更新前的?【1号员工更新了,只是用的key不同】 */ @CachePut(/*value = "emp",*/key = "#result.id") public Employee updateEmp(Employee employee){ System.out.println("updateEmp:"+employee); employeeMapper.updateEmp(employee); return employee; } /** * @CacheEvict:缓存清除 * key:指定要清除的数据 * allEntries=true:指定清除这个缓存中全部数据 * beforeInvocation=false:缓存的清除是否在方法以前执行 * 默认表明缓存清除操做是在方法执行以后执行;若是出现异常缓存就 * 不会清除 * * beforeInvocation = true: * 表明清除缓存操做是在方法运行以前执行,不管是否出现异常,缓存都清除 */ @CacheEvict(/*value = "emp",*/beforeInvocation = true/*,key = "#id"*/) public void deleteEmp(Integer id){ System.out.println("deleteEmp:"+id); /*employeeMapper.deleteEmpById(id);*/ } /** * @Caching 定义复杂的缓存规则 * 这里意味着当你再用id或email调用时,则不须要再执行SQL语句 * @param lastName * @return */ @Caching( cacheable = { @Cacheable(/*value = "emp",*/key = "#lastName") }, put = { @CachePut(/*value = "emp",*/key = "#result.id"), @CachePut(/*value = "emp",*/key = "#result.email")//有@CachePut出现,下面的方法就必定会执行 } ) //你依照id,邮箱,名字均可以得到该value public Employee getEmpByLastName(String lastName){ System.out.println("复杂缓存"); return employeeMapper.getEmpByLastName(lastName); } }
` 这里主要说了SpringCache注解的功能,而且更加详细数据库
可是我在另外一项目中使用这些注解却出现了一些意外主要是由于key本来是String类型,可是我没有将负值key为id的属性转成String,这里则说明有些须要转型,有些则不须要:数组
`缓存
package cn.enilu.subor.service.system.impl; import cn.enilu.subor.bean.entity.system.Video; import cn.enilu.subor.dao.system.VideoRepository; import cn.enilu.subor.service.system.VideoService; import cn.enilu.subor.utils.factory.MutiStrFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; @CacheConfig(cacheNames = "video") @Service public class VideoServiceImpl implements VideoService { @Autowired private VideoRepository videoRepository; @Override public Page<Video> findAll(Pageable var1) { return videoRepository.findAll(var1); } @Override //@Cacheable(value = {"video"}) public List<Video> findAll() { return videoRepository.findAll(); } @Override @CachePut(key = "#video.id.toString()") public Video save(Video video) { return videoRepository.save(video); } @Override @CacheEvict(key = "#id.toString()") public void delete(Integer id) { System.out.println("dddddddddddddddddddd"+id); videoRepository.delete(id); } @CachePut(key = "#video.id.toString()") public void update(Video video){ System.out.println("uuuuuuu"); System.out.println("38218401779274902148901249012"+video); Integer videoId=video.getId(); //String title=video.getTitle(); String video_introduce=video.getVideoIntroduce(); String video_type=video.getVideoType(); Integer video_class=video.getVideoClass(); //String video_url=video.getVideoUrl(); //String img_title=video.getImgTitle(); // String img_url=video.getImgUrl(); videoRepository.updateById2(video_class,video_introduce,video_type,videoId); } }
`app
这里在附上注解的源码,key的类型为Stringless
`dom
package org.springframework.cache.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface CachePut { @AliasFor("cacheNames") String[] value() default {}; @AliasFor("value") String[] cacheNames() default {}; String key() default ""; String keyGenerator() default ""; String cacheManager() default ""; String cacheResolver() default ""; String condition() default ""; String unless() default ""; }
`异步