###1、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
###2、实际例子
基于上一篇《纯java实现缓存》,咱们这里从新定义业务类(MyAccountService)和测试类(Main),自定义的缓存管理器类不须要了,由于spring已经为咱们提供了。
从新定义服务类以下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.业务类code
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.测试方法xml
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...张三 去数据库查询