一、简介
1、缓存先容
Spring 从 3.1 开始就引入了对 Cache 的支持。界说了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来同一差异的缓存技能。并支持使用 JCache(JSR-107)注解简化我们的开辟。
其使用方法和原理都雷同于 Spring 对事务管理的支持。Spring Cache 是作用在方法上的,其焦颔首脑是,当我们在调用一个缓存方法时会把该方法参数和返回效果作为一个键值对存在缓存中。
2、Cache 和 CacheManager 接口分析
Cache 接口包罗缓存的各种操纵聚集,你操纵缓存就是通过这个接口来操纵的。
Cache 接口下 Spring 提供了各种 xxxCache 的实现,比如:RedisCache、EhCache、ConcurrentMapCache
CacheManager 界说了创建、设置、获取、管理和控制多个唯肯定名的 Cache。这些 Cache 存在于 CacheManager 的上下文中。
小结:
每次调用须要缓存功能的方法时,Spring 会查抄指定参数的指定目的方法是否已经被调用过,假如有就直接从缓存中获取方法调用后的效果,假如没有就调用方法并缓存效果后返回给用户。下次调用直接从缓存中获取。
二、@Cacheable 注解使用详细先容
@Cacheable 这个注解,用它就是为了使用缓存的。以是我们可以先说一下缓存的使用步调:
1、缓存使用步调
1、开启基于注解的缓存,使用 @EnableCaching 标识在 SpringBoot 的主启动类上。2、标注缓存注解即可① 第一步:开启基于注解的缓存,使用 @EnableCaching 标注在 springboot 主启动类上
@EnableSwagger2@EnableScheduling@EnableFeignClients(basePackages = {"src.main.biz.smallProject.client","com.codingapi.tx"})@EnableJpaRepositories(basePackages = {"src.main.biz.smallProject.web.*.dao","src.main.newgrand.framework.common.dao" })@EntityScan(basePackages = { "src.main.biz.smallProject.web.*.entity","src.main.newgrand.framework.common.domain"})@EnableCachingpublic class StartApp { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(StartApp.class); new SpringUtil().setApplicationContext(context); }}② 第二步:标注缓存注解
package src.main.biz.smallProject.web.cost.service.impl;import com.querydsl.core.BooleanBuilder;import com.querydsl.core.QueryResults;import com.querydsl.core.types.Projections;import com.querydsl.jpa.impl.JPAQueryFactory;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import src.main.biz.smallProject.utils.CollectionUtils;import src.main.biz.smallProject.web.construct.form.IdsForm;import src.main.biz.smallProject.web.cost.dao.BusinessScopeJPA;import src.main.biz.smallProject.web.cost.entity.BusinessScopeEntity;import src.main.biz.smallProject.web.cost.entity.QBusinessScopeEntity;import src.main.biz.smallProject.web.cost.form.BusinessScopeForm;import src.main.biz.smallProject.web.cost.form.BusinessScopeQueryForm;import src.main.biz.smallProject.web.cost.service.BusinessScopeService;import src.main.biz.smallProject.web.cost.vo.BusinessScopeVO;import src.main.newgrand.framework.common.constants.PageData;import src.main.newgrand.framework.common.exception.BusinessException;import src.main.newgrand.framework.common.service.impl.BaseServiceImpl;import src.main.newgrand.framework.common.utils.ResultRes;import java.time.LocalDateTime;import java.util.List;import static src.main.biz.smallProject.redis.CacheConstants.BUSINESS_SCOPE_CACHE;/** * @Description * @Author yql * @Date 2022-05-10 10:44:29 */@Servicepublic class BusinessScopeServiceImpl extends BaseServiceImpl<BusinessScopeJPA, BusinessScopeEntity, BusinessScopeVO> implements BusinessScopeService { @Autowired private JPAQueryFactory jpaQueryFactory; QBusinessScopeEntity qBusinessScopeEntity = QBusinessScopeEntity.businessScopeEntity; @Autowired private BusinessScopeService businessScopeService; @Override @Transactional(rollbackFor = BusinessException.class) @CacheEvict(cacheNames = {BUSINESS_SCOPE_CACHE}, allEntries = true) public ResultRes add(BusinessScopeForm form) { BusinessScopeEntity businessScopeEntity = new BusinessScopeEntity(); BeanUtils.copyProperties(form,businessScopeEntity); businessScopeService.save(businessScopeEntity); return ResultRes.success(); } @Override @Transactional(rollbackFor = BusinessException.class) @CacheEvict(cacheNames = {BUSINESS_SCOPE_CACHE}, allEntries = true) public ResultRes update(BusinessScopeForm form) { BusinessScopeEntity businessScopeEntity = findById(form.getPhid()); if(businessScopeEntity == null){ throw new BusinessException("数据不存在,请查抄!"); } BeanUtils.copyProperties(form,businessScopeEntity); businessScopeService.updateSelectiveById(businessScopeEntity); return ResultRes.success(); } @Override @Cacheable(cacheNames = BUSINESS_SCOPE_CACHE, key = "{ " + "#root.methodName, #form.status}", unless = "#result == null") public ResultRes<ageData> list(BusinessScopeQueryForm form) { long currPage = form.getCurrent(); long size = form.getSize(); BooleanBuilder booleanBuilder = new BooleanBuilder(); booleanBuilder.and(qBusinessScopeEntity.phDelflag.eq(0L)); if(form.getStatus() != null){ booleanBuilder.and(qBusinessScopeEntity.status.eq(form.getStatus())); } QueryResults<BusinessScopeVO> results = jpaQueryFactory .select(Projections.bean( BusinessScopeVO.class, qBusinessScopeEntity.phid, qBusinessScopeEntity.name, qBusinessScopeEntity.status)) .from(qBusinessScopeEntity) .where(booleanBuilder) .orderBy(qBusinessScopeEntity.phInsertDt.desc()) .offset((currPage - 1) * size) .limit(size).fetchResults(); PageData pageData = new PageData(results.getResults(), results.getTotal(), size, currPage); return ResultRes.success(pageData); } @Override @Transactional(rollbackFor = BusinessException.class) @CacheEvict(cacheNames = {BUSINESS_SCOPE_CACHE}, allEntries = true) public ResultRes deleteData(IdsForm form) { List<Long> ids = form.getIds(); List<BusinessScopeEntity> businessScopeEntityList = queryFactory.selectFrom(qBusinessScopeEntity) .where(qBusinessScopeEntity.phid.in(ids).and(qBusinessScopeEntity.phDelflag.eq(0L))) .fetch(); if(CollectionUtils.isEmpty(businessScopeEntityList)){ throw new BusinessException("数据不存在,请查抄!"); } queryFactory.update(qBusinessScopeEntity) .set(qBusinessScopeEntity.phDelflag, 1L) .set(qBusinessScopeEntity.phUpdateDt, LocalDateTime.now()) .where(qBusinessScopeEntity.phid.in(ids)) .execute(); return ResultRes.success(); }}2、常用属性分析
cacheNames/value :用来指定缓存组件的名字key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)keyGenerator :key 的天生器。 key 和 keyGenerator 二选一使用cacheManager :可以用来指定缓存管理器。从哪个缓存管理器内里获取缓存。condition :可以用来指定符合条件的情况下才缓存unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。固然你也可以获取到效果举行判定。(通过 #result 获取方法效果)sync :是否使用异步模式。3、spEL 编写 key
前面说过,缓存的 key 支持使用 spEL 表达式去编写,下面总结一下使用 spEL 去编写 key 可以用的一些元数据:
|