###一、spring提供如下注解来支持spring cache
####1.@Cacheable
使用@Cacheable标记的方法,在执行该方法时,spring先去缓存中查询一次,如果查询到结果,直接返回结果(即该方法实际不会被执行);否则,执行该方法,将结果缓存。
@Cacheable可以标记在一个方法(表示该方法支持缓存)或标记在一个类上(该类的所有方法均支持缓存)
需要注意的是:支持缓存的方法在对象内部被调用时是不会触发缓存功能的
@Cacheable指定属性有:
value 缓存空间名称
key 缓存的key,根据这个key去上述缓存空间中查询对象值
condition 缓存的条件,可以为空。可以使用spel编写返回true或false,只有true时才进行缓存
####2.@CachePut
使用@CachePut标记的方法,在执行该方法时,每次都执行实际方法,将结果缓存。
####3.@CacheEvict
使用@CacheEvict标记的方法,会在方法执行之前或之后移除springCache中某些元素
@CacheEvict指定的属性有:
value:缓存空间名称
key:缓存的key
condition:缓存条件
allEntries:是否清空所有缓存内容,缺省值为false,如果指定true,则方法调用后立即清除所有的缓存
beforeInvocation:是否在执行方法之前就清空所有的缓存,缺省值false,如果指定true,则方法还没有执行前就清空缓存;缺省情况下,如果方法抛出异常,则不会清空缓存
####4.@Caching
它可以让我们在一个方法或类上同时指定多个spring cache相关注解
###二、实际例子
基于上一篇《纯java实现缓存》,我们这里重新定义业务类(MyAccountService)和测试类(Main),自定义的缓存管理器类不需要了,因为spring已经为我们提供了。
重新定义服务类如下
package com.test.spring.cacheCommon;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
/**
* 业务类
*/
public class MyAccountService {
/**
* 该注解的意思是:当调用getAccountByName这个方法时,spring会从一个名叫accountCache的缓存空间中查询
* 注意:1.这里没有指定查询的key,所以spting默认传参name作为key,value为Account对象。
* 2.accountCache这个名称需要在spring的xml文件中配置
* 如果查询到了,则直接返回结果,不执行getAccountByName方法
* 否则,执行getAccountByName方法,并将查询结果缓存起来
*/
@Cacheable(value="accountCache")
//根据key获取对象值
public Account getAccountByName(String name){
Account result = getFromDB(name);
return result;
}
/**
* 清除这个key值(account.getName())的对象值
*/
@CacheEvict(value="accountCache",key="#account.getName()")
public void updateAccount(Account account){
updateFromDB(account);
}
//数据库查询账号信息
private Account getFromDB(String name) {
System.out.println("去数据库查询");
return new Account(name);
}
//更新账号信息
private void updateFromDB(Account account){
System.out.println("更新账号信息"+account.getName());
}
}
测试类如下
package com.test.spring.cacheCommon;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 测试类
*
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("springCacheCommon.xml");
MyAccountService myAccountService = (MyAccountService) ctx.getBean("myAccountService");
//第一次查询,去数据库查询
myAccountService.getAccountByName("张三");
//第二次查询,从缓存中查询
myAccountService.getAccountByName("张三");
//清空缓存
Account account1 = myAccountService.getAccountByName("张三");
myAccountService.updateAccount(account1);
//第三次查询,从数据库查询
myAccountService.getAccountByName("张三");
//第四次查询,从缓存中查询
myAccountService.getAccountByName("张三");
}
}
xml文件配置如下
<!-- 服务bean配置 -->
<bean id="myAccountService" class="com.test.spring.cacheCommon.MyAccountService"></bean>
<!-- 配置缓存管理器
1.它有一个属性caches,即这个管理器所有的空间名称的集合
2.如果方法上缺省空间名称,则默认为default
3.我们还定义了一个名字叫做 accountCache
4.使用了缺省的内存方案ConcurrentMapCacheFactoryBean,它是基于java.util.concurrent.ConcurrentHashMap的一个内存缓存实现方法
-->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"></bean>
<!-- 指定spring缓存空间名称 -->
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="accountCache"></bean>
</set>
</property>
</bean>
<!-- 启用缓存注解 -->
<cache:annotation-driven cache-manager="cacheManager"/>
输出结果
去数据库查询
更新账号信息张三
去数据库查询
###多个参数时,如何制定key
1.修改基础bean
public class Account {
private int id;
private String name;
//新增字段
private String password;
}
2.业务类
public class MyAccountService {
/**
* 注意 key的组合
*/
@Cacheable(value="accountCache",key="#name.concat(#password)")
//根据key获取对象值
public Account getAccountByName(String name,String password){
Account result = getFromDB(name,password);
return result;
}
//数据库查询账号信息
private Account getFromDB(String name,String password) {
System.out.println("去数据库查询");
return new Account(name,password);
}
}
3.测试方法
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("springCacheCommon.xml");
MyAccountService myAccountService = (MyAccountService) ctx.getBean("myAccountService");
//第一次查询,去数据库查询
myAccountService.getAccountByName("张三","123456");
//第二次查询,从缓存中查询
myAccountService.getAccountByName("张三","123456");
//第三次查询,从数据库查询
myAccountService.getAccountByName("张三","654321");
//第四次查询,从缓存中查询
myAccountService.getAccountByName("张三","654321");
}
}
###@CachePut注解使用
实际的工程中,存在这种情况,我们希望某一个方法每次执行都必须被调用,因为这个方法不仅仅只返回结果,还做了其它的事情,比如:记录日志等。因此这个时候要使用@CachePut注解,它能保证该方法一定被执行,同时返回值被记录到缓存中。
业务类
package com.test.spring.cacheCommon;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
/**
* 业务类
*/
public class MyAccountService {
/**
* key的组合使用
*/
@Cacheable(value="accountCache",key="#name.concat(#password)")
//根据key获取对象值
public Account getAccountByName(String name,String password){
Account result = getFromDB(name,password);
return result;
}
/**
*
* @CachePut使用
*
*/
@CachePut(value="accountCache",key="#account.getName()")
public Account updateAccount(Account account) {
return updateDB(account);
}
//更新账号信息
private Account updateDB(Account account) {
System.out.println("real updating db..."+account.getName());
return account;
}
//数据库查询账号信息
private Account getFromDB(String name,String password) {
System.out.println("去数据库查询");
return new Account(name,password);
}
}
测试类
package com.test.spring.cacheCommon;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 测试类
*
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("springCacheCommon.xml");
MyAccountService myAccountService = (MyAccountService) ctx.getBean("myAccountService");
//第一次查询,去数据库查询
myAccountService.getAccountByName("张三","123456");
//第二次查询,从缓存中查询
myAccountService.getAccountByName("张三","123456");
//
Account account = myAccountService.getAccountByName("张三", "123456");
myAccountService.updateAccount(account);
//第三次查询,从数据库查询
myAccountService.getAccountByName("张三","123456");
//第四次查询,从数据库查询
myAccountService.getAccountByName("张三","654321");
//第五次查询,从缓存中查询
myAccountService.getAccountByName("张三","654321");
}
}
输出结果
去数据库查询
real updating db...张三
去数据库查询
来源:oschina
链接:https://my.oschina.net/u/2312022/blog/742505
