详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
注释介绍
@Cacheable
@Cacheable的作用主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@Cacheable作用和配置方法
参数
解释
example
value
缓存的名称,在spring配置文件中定义,必须指定至少一个
例如:
@Cacheable(value=”mycache”)
@Cacheable(value={”cache1”,”cache2”}
key
缓存的key,可以为空,如果指定要按照SpEL表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
@Cacheable(value=”testcache”,key=”#userName”)
condition
缓存的条件,可以为空,使用SpEL编写,返回true或者false,只有为true才进行缓存
@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
实例
@Cacheable(value=”accountCache”),这个注释的意思是,当调用这个方法的时候,会从一个名叫accountCache的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。这里的缓存中的key就是参数userName,value就是Account对象。“accountCache”缓存是在spring*.xml中定义的名称。
@Cacheable(value="accountCache")//使用了一个缓存名叫accountCache publicAccountgetAccountByName(StringuserName){ //方法内部实现不考虑缓存逻辑,直接实现业务 System.out.println("realqueryaccount."+userName); returngetFromDB(userName); }
@CachePut
@CachePut的作用主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用
@CachePut作用和配置方法
参数
解释
example
value
缓存的名称,在spring配置文件中定义,必须指定至少一个
@CachePut(value=”mycache”)
key
缓存的key,可以为空,如果指定要按照SpEL表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
@CachePut(value=”testcache”,key=”#userName”)
condition
缓存的条件,可以为空,使用SpEL编写,返回true或者false,只有为true才进行缓存
@CachePut(value=”testcache”,condition=”#userName.length()>2”)
实例
@CachePut注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
@CachePut(value="accountCache",key="#account.getName()")//更新accountCache缓存 publicAccountupdateAccount(Accountaccount){ returnupdateDB(account); }
@CacheEvict
@CachEvict的作用主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict作用和配置方法
参数
解释
example
value
缓存的名称,在spring配置文件中定义,必须指定至少一个
@CacheEvict(value=”mycache”)
key
缓存的key,可以为空,如果指定要按照SpEL表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
@CacheEvict(value=”testcache”,key=”#userName”)
condition
缓存的条件,可以为空,使用SpEL编写,返回true或者false,只有为true才进行缓存
@CacheEvict(value=”testcache”,condition=”#userName.length()>2”)
allEntries
是否清空所有缓存内容,缺省为false,如果指定为true,则方法调用后将立即清空所有缓存
@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation
是否在方法执行前就清空,缺省为false,如果指定为true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
@CachEvict(value=”testcache”,beforeInvocation=true)
实例
@CacheEvict(value="accountCache",key="#account.getName()")//清空accountCache缓存 publicvoidupdateAccount(Accountaccount){ updateDB(account); } @CacheEvict(value="accountCache",allEntries=true)//清空accountCache缓存 publicvoidreload(){ reloadAll() } @Cacheable(value="accountCache",condition="#userName.length()<=4")//缓存名叫accountCache publicAccountgetAccountByName(StringuserName){ //方法内部实现不考虑缓存逻辑,直接实现业务 returngetFromDB(userName); }
@CacheConfig
所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完那就省事了,所以,有了@CacheConfig这个配置,@CacheConfigisaclass-levelannotationthatallowstosharethecachenames,如果你在你的方法写别的名字,那么依然以方法的名字为准。
@CacheConfig("books") publicclassBookRepositoryImplimplementsBookRepository{ @Cacheable publicBookfindBook(ISBNisbn){...} }
条件缓存
下面提供一些常用的条件缓存
//@Cacheable将在执行方法之前(#result还拿不到返回值)判断condition,如果返回true,则查缓存; @Cacheable(value="user",key="#id",condition="#idlt10") publicUserconditionFindById(finalLongid) //@CachePut将在执行完方法后(#result就能拿到返回值了)判断condition,如果返回true,则放入缓存; @CachePut(value="user",key="#id",condition="#result.usernamene'zhang'") publicUserconditionSave(finalUseruser) //@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反) @CachePut(value="user",key="#user.id",unless="#result.usernameeq'zhang'") publicUserconditionSave2(finalUseruser) //@CacheEvict,beforeInvocation=false表示在方法执行之后调用(#result能拿到返回值了);且判断condition,如果返回true,则移除缓存; @CacheEvict(value="user",key="#user.id",beforeInvocation=false,condition="#result.usernamene'zhang'") publicUserconditionDelete(finalUseruser)
@Caching
有时候我们可能组合多个Cache注解使用;比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;此时就需要@Caching组合多个注解标签了。
@Caching(put={ @CachePut(value="user",key="#user.id"), @CachePut(value="user",key="#user.username"), @CachePut(value="user",key="#user.email") }) publicUsersave(Useruser){
自定义缓存注解
比如之前的那个@Caching组合,会让方法上的注解显得整个代码比较乱,此时可以使用自定义注解把这些注解组合到一个注解中,如:
@Caching(put={ @CachePut(value="user",key="#user.id"), @CachePut(value="user",key="#user.username"), @CachePut(value="user",key="#user.email") }) @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public@interfaceUserSaveCache{ }
这样我们在方法上使用如下代码即可,整个代码显得比较干净。
@UserSaveCache publicUsersave(Useruser)
扩展
比如findByUsername时,不应该只放username–>user,应该连同id—>user和email—>user一起放入;这样下次如果按照id查找直接从缓存中就命中了
@Caching( cacheable={ @Cacheable(value="user",key="#username") }, put={ @CachePut(value="user",key="#result.id",condition="#result!=null"), @CachePut(value="user",key="#result.email",condition="#result!=null") } ) publicUserfindByUsername(finalStringusername){ System.out.println("cachemiss,invokefindbyusername,username:"+username); for(Useruser:users){ if(user.getUsername().equals(username)){ returnuser; } } returnnull; }
其实对于:id—>user;username—->user;email—>user;更好的方式可能是:id—>user;username—>id;email—>id;保证user只存一份;如:
@CachePut(value="cacheName",key="#user.username",cacheValue="#user.username") publicvoidsave(Useruser) @Cacheable(value="cacheName",key="#user.username",cacheValue="#caches[0].get(#caches[0].get(#username).get())") publicUserfindByUsername(Stringusername)
SpEL上下文数据
SpringCache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:
名称
位置
描述
示例
methodName
root对象
当前被调用的方法名
root.methodName
method
root对象
当前被调用的方法
root.method.name
target
root对象
当前被调用的目标对象
root.target
targetClass
root对象
当前被调用的目标对象类
root.targetClass
args
root对象
当前被调用的方法的参数列表
root.args[0]
caches
root对象
当前方法调用使用的缓存列表(如@Cacheable(value={“cache1”,“cache2”})),则有两个cache
root.caches[0].name
argumentname
执行上下文
当前被调用的方法的参数,如findById(Longid),我们可以通过#id拿到参数
user.id
result
执行上下文
方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless','cacheevict'的beforeInvocation=false)
result
@CacheEvict(value="user",key="#user.id",condition="#root.target.canCache()and#root.caches[0].get(#user.id).get().usernamene#user.username",beforeInvocation=true) publicvoidconditionUpdate(Useruser)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。