SpringBoot数据访问-------------数据缓存
Posted 没昵称可用
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot数据访问-------------数据缓存相关的知识,希望对你有一定的参考价值。
Spring缓存支持
Spring开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术。Spring Cache的核心就是对某个方法进行缓存,其实质就是缓存该方法的返回结果,并把方法参数和结果用键值对的方式存放到缓存中,当再次调用该方法使用相应的参数时,就会直接从缓存里面取出指定的结果进行返回。所以在使用Cache的时候我们要保证我们缓存的方法对于相同的参数要有相同的返回结果。
自定义缓存
定义实体类
public class Account { private int id; private String name; public Account(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
定义一个缓存管理器
import com.google.common.collect.Maps; import java.util.Map; public class CacheContext<T> { private Map<String, T> cache = Maps.newConcurrentMap(); public T get(String key){ return cache.get(key); } public void addOrUpdateCache(String key,T value) { cache.put(key, value); } // 依据 key 来删除缓存中的一条记录 public void evictCache(String key) { if(cache.containsKey(key)) { cache.remove(key); } } // 清空缓存中的全部记录 public void evictCache() { cache.clear(); } }
定义服务类
import com.google.common.base.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class AccountService1 { private final Logger logger = LoggerFactory.getLogger(AccountService1.class); @Resource private CacheContext<Account> accountCacheContext; public Account getAccountByName(String accountName) { Account result = accountCacheContext.get(accountName); if (result != null) { logger.info("get from cache... {}", accountName); return result; } Optional<Account> accountOptional = getFromDB(accountName); if (!accountOptional.isPresent()) { throw new IllegalStateException(String.format("can not find account by account name : [%s]", accountName)); } Account account = accountOptional.get(); accountCacheContext.addOrUpdateCache(accountName, account); return account; } public void reload() { accountCacheContext.evictCache(); } private Optional<Account> getFromDB(String accountName) { logger.info("real querying db... {}", accountName); //Todo query data from database return Optional.fromNullable(new Account(accountName)); } }
Spring Cache
注解 描述
@Cacheable 在方法执行前Spring先查看缓存中是否有数据,如果有数据则直接返回缓存数据。反之调用方法并将方法返回值放入缓存填充。
@CachePut 无论缓存是否有数据,都会将方法的返回值放入缓存。
@CacheEvict 将一条或多条数据从缓存中删除。
@Caching 组合多个注解策略在一个方法上。
Spring Cache实例
package com.kingdee.service; import java.util.Optional; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.kingdee.domains.Account; @Service public class AccountService { @Cacheable(value="accountCache") public Account getAccountByName(String accountName) { System.out.println("real querying account... "+accountName); // 方法内部实现不考虑缓存逻辑,直接实现业务 Account accountOptional = getFromDB(accountName); return accountOptional; } @CacheEvict(value="accountCache",key="#account.getName()") public void updateAccount(Account account) { updateDB(account); } @CachePut(value="accountCache",key="#account.getName()") public Account updateAccount2(Account account){ account.setName("bcd"); System.out.println("========="+account.getName()); return account; } private void updateDB(Account account) { System.out.println("real update db..."+account.getName()); } private Account getFromDB(String accountName) { System.out.println("real querying db... "+accountName); Account account = new Account(accountName); return account; } }
Spring配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" xmlns:rabbit="http://www.springframework.org/schema/rabbit" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <context:component-scan base-package="com.kingdee"></context:component-scan> <context:annotation-config/> <cache:annotation-driven/> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"> <property name="name" value="default"/> </bean> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"> <property name="name" value="accountCache"/> </bean> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"> <property name="name" value="myCache"/> </bean> </set> </property> </bean> </beans>
测试
package com.kingdee; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kingdee.domains.Account; import com.kingdee.domains.User; import com.kingdee.service.AccountService; import com.kingdee.service.UserService; public class CacheTest { public static void main(String[] args){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-beans.xml"); AccountService accountService = context.getBean("accountService", AccountService.class); Account account = accountService.getAccountByName("abc"); Account account2 = accountService.getAccountByName("abc"); UserService userService = context.getBean("userService", UserService.class); User user = userService.findName("abc"); System.out.println("==========="+user.getName()); User user2 = userService.findName("abc"); System.out.println("==========="+user2.getName()); } }
注解详解
缓存@Cacheable
@Cacheable
注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存。
@Cacheable(value = "emp" ,key = "targetClass + methodName +#p0") public List<NewJob> queryAll(User uid) { return newJobDao.findAllByUid(uid); }
此处的value
是必需的,它指定了你的缓存存放在哪块命名空间。
此处的key
是使用的spEL表达式,参考上章。这里有一个小坑,如果你把methodName
换成method
运行会报错,观察它们的返回类型,原因在于methodName
是String
而methoh
是Method
。
源码分析
String[] cacheNames() default {}; //和value注解差不多,二选一 String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用 String cacheManager() default ""; //指定缓存管理器 String cacheResolver() default ""; //或者指定获取解析器 String condition() default ""; //条件符合则缓存 String unless() default ""; //条件符合则不缓存 boolean sync() default false; //是否使用异步模式
配置@CacheConfig
当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {"myCache"})
注解来统一指定value
的值,这时可省略value
,如果你在你的方法依旧写上了value
,那么依然以方法的value
值为准。
@CacheConfig(cacheNames = {"myCache"}) public class BotRelationServiceImpl implements BotRelationService { @Override @Cacheable(key = "targetClass + methodName +#p0")//此处没写value public List<BotRelation> findAllLimit(int num) { return botRelationRepository.findAllLimit(num); } ..... }
源码分析
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用 String cacheManager() default ""; //指定缓存管理器 String cacheResolver() default ""; //或者指定获取解析器
更新@CachePut
@CachePut
注解的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable
不同的是,它每次都会触发真实方法的调用 。简单来说就是用户更新缓存数据。但需要注意的是该注解的value
和 key
必须与要更新的缓存相同,也就是与@Cacheable
相同。示例:
@CachePut(value = "emp", key = "targetClass + #p0") public NewJob updata(NewJob job) { NewJob newJob = newJobDao.findAllById(job.getId()); newJob.updata(job); return job; }
源码分析
String[] cacheNames() default {}; //与value二选一 String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用 String cacheManager() default ""; //指定缓存管理器 String cacheResolver() default ""; //或者指定获取解析器 String condition() default ""; //条件符合则缓存 String unless() default ""; //条件符合则不缓存
清除@CacheEvict
@CachEvict
的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空 。
@CacheEvict(value="emp",key="#id") public void delect(int id) { newJobDao.deleteAllById(id); }
源码分析
String[] cacheNames() default {}; //与value二选一 String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用 String cacheManager() default ""; //指定缓存管理器 String cacheResolver() default ""; //或者指定获取解析器 String condition() default ""; //条件符合则清空
SpringBoot实例
在Springboot运行时开启缓存支持
package com.kingdee; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ImportResource; @SpringBootApplication @EnableCaching public class App { public static void main(String[] args){ SpringApplication.run(App.class); } }
以上是关于SpringBoot数据访问-------------数据缓存的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot:Mybatis + Druid 数据访问