详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
https://blog.csdn.net/u012240455/article/details/80844361
注释介绍
@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 中定义的名称。
|
1
2
3
4
5
6
|
@Cacheable(value="accountCache")// 使用了一个缓存名叫 accountCachepublic Account getAccountByName(String userName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 System.out.println("real query account."+userName); return getFromDB(userName);} |
@CachePut
@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
@CachePut 作用和配置方法
| 参数 | 解释 | example |
|---|---|---|
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @CachePut(value=”my cache”) |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @CachePut(value=”testcache”,key=”#userName”) |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @CachePut(value=”testcache”,condition=”#userName.length()>2”) |
实例
@CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
|
1
2
3
4
|
@CachePut(value="accountCache",key="#account.getName()")// 更新accountCache 缓存public Account updateAccount(Account account) { return updateDB(account);} |
@CacheEvict
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict 作用和配置方法
| 参数 | 解释 | example |
|---|---|---|
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @CacheEvict(value=”my cache”) |
| 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) |
实例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@CacheEvict(value="accountCache",key="#account.getName()")// 清空accountCache 缓存public void updateAccount(Account account) { updateDB(account);}@CacheEvict(value="accountCache",allEntries=true)// 清空accountCache 缓存public void reload() { reloadAll()}@Cacheable(value="accountCache",condition="#userName.length() <=4")// 缓存名叫 accountCachepublic Account getAccountByName(String userName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 return getFromDB(userName);} |
@CacheConfig
所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在你的方法写别的名字,那么依然以方法的名字为准。
|
1
2
3
4
5
6
|
@CacheConfig("books")public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...}} |
条件缓存
下面提供一些常用的条件缓存
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//@Cacheable将在执行方法之前( #result还拿不到返回值)判断condition,如果返回true,则查缓存;@Cacheable(value = "user", key = "#id", condition = "#id lt 10")public User conditionFindById(final Long id)//@CachePut将在执行完方法后(#result就能拿到返回值了)判断condition,如果返回true,则放入缓存;@CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")public User conditionSave(final User user) //@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反)@CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")public User conditionSave2(final User user) //@CacheEvict, beforeInvocation=false表示在方法执行之后调用(#result能拿到返回值了);且判断condition,如果返回true,则移除缓存;@CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'")public User conditionDelete(final User user) |
@Caching
有时候我们可能组合多个Cache注解使用;比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;此时就需要@Caching组合多个注解标签了。
|
1
2
3
4
5
6
|
@Caching(put = {@CachePut(value = "user", key = "#user.id"),@CachePut(value = "user", key = "#user.username"),@CachePut(value = "user", key = "#user.email")})public User save(User user) { |
自定义缓存注解
比如之前的那个@Caching组合,会让方法上的注解显得整个代码比较乱,此时可以使用自定义注解把这些注解组合到一个注解中,如:
|
1
2
3
4
5
6
7
8
9
10
|
@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)@Inheritedpublic @interface UserSaveCache {} |
这样我们在方法上使用如下代码即可,整个代码显得比较干净。
|
1
2
|
@UserSaveCachepublic User save(User user) |
扩展
比如findByUsername时,不应该只放username–>user,应该连同id—>user和email—>user一起放入;这样下次如果按照id查找直接从缓存中就命中了
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@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") })public User findByUsername(final String username) { System.out.println("cache miss, invoke find by username, username:" + username); for (User user : users) { if (user.getUsername().equals(username)) { return user; } } return null;} |
其实对于:id—>user;username—->user;email—>user;更好的方式可能是:id—>user;username—>id;email—>id;保证user只存一份;如:
|
1
2
3
4
5
6
|
@CachePut(value="cacheName", key="#user.username", cacheValue="#user.username")public void save(User user) @Cacheable(value="cacheName", key="#user.username", cacheValue="#caches[0].get(#caches[0].get(#username).get())")public User findByUsername(String username) |
SpEL上下文数据
Spring Cache提供了一些供我们使用的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 |
| argument name | 执行上下文 | 当前被调用的方法的参数,如findById(Long id),我们可以通过#id拿到参数 | user.id |
| result | 执行上下文 | 方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless','cache evict'的beforeInvocation=false) | result |
|
1
2
|
@CacheEvict(value = "user", key = "#user.id", condition = "#root.target.canCache() and #root.caches[0].get(#user.id).get().username ne #user.username", beforeInvocation = true)public void conditionUpdate(User user) |
详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用的更多相关文章
- Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用(转)
原文地址:https://www.cnblogs.com/fashflying/p/6908028.html 从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对 ...
- Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
- Spring缓存注解@Cache,@CachePut , @CacheEvict,@CacheConfig使用
@Cacheable.@CachePut.@CacheEvict 注释介绍 表 1. @Cacheable 作用和配置方法 @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结 ...
- Spring Boot缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
- 缓存注解@Cacheable、@CacheEvict、@CachePut使用及注解失效时间
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
- Spring-Cache 注解 @Cacheable,@CachePut , @CacheEvict
1.自动生成key @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Ob ...
- Spring缓存注解@Cacheable
@Cacheable @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @Cacheable 作用和配置方法 参数 解释 example value 缓存的名称, ...
- Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常
代码: @Override @Cacheable(value = CACHE_NAME, key = "'CartItemkey_'+#uId") public List<S ...
- Spring缓存注解@CachePut , @CacheEvict,@CacheConfig使用
Cacheable CachePut CacheEvict CacheConfig 开启缓存注解 @Cacheable @Cacheable是用来声明方法是可缓存的.将结果存储到缓存中以便后续使用相同 ...
随机推荐
- spring学习-ApplicationContext-spring上下文深入理解
4月份开始复习一遍spring相关知识.让自己巩固一下spring大法的深奥益处,所以就看了大佬的博客,转载留下来日后继续研读.认为重点的标记为红色 以下文章内容转载自:http://www.cnbl ...
- Ribbon核心组件IRule及配置指定的负载均衡算法
Ribbon在工作时分为两步: 第一步:先选择 EurekaServer,它优先选择在同一个区域内负载较少的Server: 第二步:再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地 ...
- [C++基础] 变量、关键字、运算符、位操作篇
一.变量篇 1 全局变量和静态变量有什么异同? 相同:都在静态存储区分配空间,生命周期与程序生命周期相同. 区别:全局变量的作用域是整个程序,它只需要在一个源文件中定义,就可以作用于所有的源文件.而静 ...
- eclipse中正确创建Django项目
本教程只说明eclipse中django项目的创建,不涉及django相关开发内容: 1."File" -> "New" -> "Othe ...
- Git/SVN提交代码规范
feat - 新功能 feature fix - 修复 bug docs - 文档注释 style - 代码格式(不影响代码运行的变动) refactor - 重构.优化(既不增加新功能,也不是修复b ...
- 在spring管理的类的要注意问题
特别时写框架的时候, 注意依赖引用,类的成员变量不要随便new,看spring容器中是否管理过,new出来的时其他的对象了
- AQS工作原理分析
AQS工作原理分析 一.大致介绍1.前面章节讲解了一下CAS,简单讲就是cmpxchg+lock的原子操作:2.而在谈到并发操作里面,我们不得不谈到AQS,JDK的源码里面好多并发的类都是通过Sy ...
- 集成开发环境(IDE)
学习目标: 1.了解Java的IDE开发工具 2.会使用Eclipse.IDEA开发工具新建项目,编写代码,并运行程序. 学习过程: 使用文本开发效率无疑是很低的,每次编写完代码后,还需要手动的编译执 ...
- Linux学习笔记之安装报错/lib/ld-linux.so.2: bad ELF interpreter
0x00 64位系统中安装了32位程序解决办法 是因为64位系统中安装了32位程序 解决方法: yum install glibc.i686 0x01 解决交叉编译环境错误 yum install l ...
- 总结:WPF中模板需要绑定父级别的ViewModel该如何处理
原文:总结:WPF中模板需要绑定父级别的ViewModel该如何处理 <ListBox ItemsSource="{Binding ClassCollection}"> ...