springcache使用笔记002_注释驱动的 Spring cache 按条件查询
来源:互联网 发布:锁屏主题软件 编辑:程序博客网 时间:2024/06/06 18:32
如何按照条件操作缓存
前面介绍的缓存方法,没有任何条件,即所有对 accountService 对象的 getAccountByName 方法的调用都会起动缓存效果,不管参数是什么值,如果有一个需求,就是只有账号名称的长度小于等于 4 的情况下,才做缓存,大于 4 的不使用缓存,那怎么实现呢?
Spring cache 提供了一个很好的方法,那就是基于 SpEL 表达式的 condition 定义,这个 condition 是 @Cacheable 注释的一个属性,下面我来演示一下
清单 13. AccountService.java(getAccountByName 方法修订,支持条件)
@Cacheable(value="accountCache",condition="#userName.length() <= 4")// 缓存名叫 accountCache
public Account getAccountByName(String userName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName);
}
注意其中的 condition=”#userName.length() <=4”,这里使用了 SpEL 表达式访问了参数 userName 对象的 length() 方法,条件表达式返回一个布尔值,true/false,当条件为 true,则进行缓存操作,否则直接调用方法执行的返回结果。
清单 14. 测试方法
s.getAccountByName("somebody");// 长度大于 4,不会被缓存
s.getAccountByName("sbd");// 长度小于 4,会被缓存
s.getAccountByName("somebody");// 还是查询数据库
s.getAccountByName("sbd");// 会从缓存返回
清单 15. 运行结果
real querying db...somebody
real querying db...sbd
real querying db...somebody
可见对长度大于 4 的账号名 (somebody) 没有缓存,每次都查询数据库。
如果有多个参数,如何进行 key 的组合
假设 AccountService 现在有一个需求,要求根据账号名、密码和是否发送日志查询账号信息,很明显,这里我们需要根据账号名、密码对账号对象进行缓存,而第三个参数“是否发送日志”对缓存没有任何影响。所以,我们可以利用 SpEL 表达式对缓存 key 进行设计
清单 16. Account.java(增加 password 属性)
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
清单 17. AccountService.java(增加 getAccount 方法,支持组合 key)
@Cacheable(value="accountCache",key="#userName.concat(#password)")
public Account getAccount(String userName,String password,boolean sendLog) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName,password);
}
注意上面的 key 属性,其中引用了方法的两个参数 userName 和 password,而 sendLog 属性没有考虑,因为其对缓存没有影响。
清单 18. Main.java
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-cache-anno.xml");// 加载 spring 配置文件
AccountService s = (AccountService) context.getBean("accountServiceBean");
s.getAccount("somebody", "123456", true);// 应该查询数据库
s.getAccount("somebody", "123456", true);// 应该走缓存
s.getAccount("somebody", "123456", false);// 应该走缓存
s.getAccount("somebody", "654321", true);// 应该查询数据库
s.getAccount("somebody", "654321", true);// 应该走缓存
}
上述测试,是采用了相同的账号,不同的密码组合进行查询,那么一共有两种组合情况,所以针对数据库的查询应该只有两次。
清单 19. 运行结果
real querying db...userName=somebody password=123456
real querying db...userName=somebody password=654321
和我们预期的一致。
如何做到:既要保证方法被调用,又希望结果被缓存
根据前面的例子,我们知道,如果使用了 @Cacheable 注释,则当重复使用相同参数调用方法的时候,方法本身不会被调用执行,即方法本身被略过了,取而代之的是方法的结果直接从缓存中找到并返回了。
现实中并不总是如此,有些情况下我们希望方法一定会被调用,因为其除了返回一个结果,还做了其他事情,例如记录日志,调用接口等,这个时候,我们可以用 @CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中。
清单 20. AccountService.java
@Cacheable(value="accountCache")// 使用了一个缓存名叫 accountCache
public Account getAccountByName(String userName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName);
}
@CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 缓存
public Account updateAccount(Account account) {
return updateDB(account);
}
private Account updateDB(Account account) {
System.out.println("real updating db..."+account.getName());
return account;
}
清单 21. Main.java
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-cache-anno.xml");// 加载 spring 配置文件
AccountService s = (AccountService) context.getBean("accountServiceBean");
Account account = s.getAccountByName("someone");
account.setPassword("123");
s.updateAccount(account);
account.setPassword("321");
s.updateAccount(account);
account = s.getAccountByName("someone");
System.out.println(account.getPassword());
}
如上面的代码所示,我们首先用 getAccountByName 方法查询一个人 someone 的账号,这个时候会查询数据库一次,但是也记录到缓存中了。然后我们修改了密码,调用了 updateAccount 方法,这个时候会执行数据库的更新操作且记录到缓存,我们再次修改密码并调用 updateAccount 方法,然后通过 getAccountByName 方法查询,这个时候,由于缓存中已经有数据,所以不会查询数据库,而是直接返回最新的数据,所以打印的密码应该是“321”
清单 22. 运行结果
real querying db...someone
real updating db...someone
real updating db...someone
321
和分析的一样,只查询了一次数据库,更新了两次数据库,最终的结果是最新的密码。说明 @CachePut 确实可以保证方法被执行,且结果一定会被缓存。
@Cacheable、@CachePut、@CacheEvict 注释介绍
通过上面的例子,我们可以看到 spring cache 主要使用两个注释标签,即 @Cacheable、@CachePut 和 @CacheEvict,我们总结一下其作用和配置方法。
表 1. @Cacheable 作用和配置方法
@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”)
表 2. @CachePut 作用和配置方法
@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”)
表 3. @CacheEvict 作用和配置方法
@CachEvict(value=”mycache”) 或者
@CachEvict(value={”cache1”,”cache2”}key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合例如:
@CachEvict(value=”testcache”,key=”#userName”)condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存例如:
@CachEvict(value=”testcache”,
condition=”#userName.length()>2”)allEntries是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存例如:
@CachEvict(value=”testcache”,allEntries=true)beforeInvocation是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存例如:
@CachEvict(value=”testcache”,beforeInvocation=true)
- springcache使用笔记002_注释驱动的 Spring cache 按条件查询
- springcache使用笔记001_注释驱动的 Spring cache 简单使用
- springcache使用笔记003_注释驱动的 Spring cache 基本原理,注意和限制,@CacheEvict 的可靠性问题
- SpringCache(Spring使用Cache)
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 注释驱动的 Spring cache 缓存介绍
- 关于前滚(roll forward)和回滚(roll back)
- 同学推荐的机器学习资料
- 找出数组中只出现一次的两个数
- 【python】pip安装报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 7: ordinal not i
- Unity2D入门手册
- springcache使用笔记002_注释驱动的 Spring cache 按条件查询
- Sqoop安装及初体验
- 正则表达式
- python生成日志
- HDU
- Java集合类系列(3)--遍历集合
- vb.net操作Excel常用命令
- white-space、word-wrap和word-break
- Dos命令查看端口占用及关闭进程