Springboot的cache缓存机制

2年前 (2022) 程序员胖胖胖虎阿
255 0 0

我们知道一个程序的瓶颈在于数据库,我们也知道内存的速度是大大快于硬盘的速度的。当我们需要重复地获取相同的数据的时候,我们一次又一次的请求数据库或者远程服务,导致大量的时间耗费在数据库查询或者远程方法调用上,导致程序性能的恶化,这便是数据缓存要解决的问题。

1.spring的缓存支持

从Spring3.1开始,定义了org.springframework.cache.CacheManager和org.springframework.cache.Cache接口用来统一不同的缓存的技术。其中,CacheManager是Spring提供的各种缓存技术抽象接口,Cache接口包含缓存的各种操作(增加、删除、获得缓存,我们一般不会直接和此接口打交道)。

1.Spring支持的CacheManager

Springboot的cache缓存机制

 在我们使用任意一个实现的CacheManager的时候,需注册实现的CacheManager的Bean,例如:

@Bean 
public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) { 
    
    return new EhCacheCacheManager(ehCacheCacheManager); 
  
} 

Springboot的cache缓存机制

2.声名式缓存注解

Spring提供了4个注解来声明缓存规则

注解 解释
@Cacheable
在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法值放进缓存
@CachePut
无论怎样,都将方法的返回值放到缓存中。

@CachePut与@Cacheable的属性一致。
@CacheEvict
将一条或多条数据从缓存中删除
@Caching 可以通过@Caching注解组合多个注册策略在一个方法上

@Cacheable、@CachePut、@CacheEvit都有value属性,指定的是要使用的缓存名称;key属性指定的是数据在缓存中的存储的键。

3.开启声名式缓存支持

开启声名式缓存支持十分简单,只需在配置类上使用@EnableCaching注解即可,例如:
 

@Configuration 
@EnableCaching 
public class AppConfig { 
  
} 

Springboot的cache缓存机制

2.Spring Boot的支持

在Spring中使用缓存技术的关键是配置CacheManager,而Spring Boot为我们自动配置了多个CacheManager的实现。
Spring Boot的CacheManager的自动配置放置在org.springframework.boot.autoconfigure.cache包中,Spring Boot为我们自动配置了EhCacheCacheConfiguration(使用EhCache)、GenericCacheConfiguration(使用Collection)、GuavaCacheConfiguration(使用Guava)、HazelcastCacheConfiguration(使用Hazelcast)、InfinispanCacheConfiguration(使用Infinispan)、JCacheCacheConfiguration(使用JCache)、NoOpCacheConfiguration(不使用存储)、RedisCacheConfiguration(使用Redis)、SimpleCacheConfiguration(使用ConcurrentMap)。在不做任何额外配置的情况下,默认使用的是SimpleCacheConfiguration,即使用ConcurrentMapCacheManager。Spring Boot支持以“spring.cache”为前缀的属性来配置缓存。

spring.cache.type= # 可选generic, ehcache, hazelcast, infinispan, jcache, redis, # guava, simple, none
spring.cache.cache-names= # 程序启动时创建缓存名称
spring.cache.ehcache.config= #  ehcache配置文件地址
spring.cache.infinispan.config= #  infinispan 配置文件地址
spring.cache.jcache.config= #  jcache 配置文件地址
spring.cache.jcache.provider= #当多个 jcache实现在类路径中的时候,指定jcache实现

在Spring Boot环境下,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在配置类使用@EnableCaching开启缓存支持即可。

代码示例

1.引入jar包

 <!--cache-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.6.6</version>
        </dependency>

2.service层

package com.demo.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.dao.SearchRecordMapper;
import com.demo.dto.SearchRecordRequest;
import com.demo.entity.SearchRecordEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.*;

/**
 * SearchRecordService
 *
 * @Description
 */
@Service
@Slf4j
public class SearchRecordService extends ServiceImpl<SearchRecordMapper, SearchRecordEntity> {

    /**
     * 获取搜索记录列表接口
     *
     * @param recordRequest
     * @return
     */
    public IPage<SearchRecordEntity> findAll(SearchRecordRequest recordRequest) {
        Map<String, Object> result = new HashMap<>();
        List<SearchRecordEntity> recordEntities = new ArrayList<>();
        IPage<SearchRecordEntity> page = new Page<>();
        page.setSize(recordRequest.getPageSize());
        page.setCurrent(recordRequest.getPage());
        QueryWrapper<SearchRecordEntity> queryWrapper = new QueryWrapper<>();

        if (StringUtils.isNotEmpty(recordRequest.getName())) {
            queryWrapper.like("name", recordRequest.getName());
        }
        queryWrapper.orderByDesc("id");
        IPage<SearchRecordEntity> searchRecords = this.page(page, queryWrapper);
        return searchRecords;
    }

    /**
     * CachePut缓存新增的或更新的数据到缓存,其中缓存名称为searchRecord,数据的key是参数的id。
     * @param searchRecordEntity
     */
    @CachePut(value = "searchRecord",key = "#p0.id")
    public void saveSearchRecord(SearchRecordEntity searchRecordEntity){
        this.save(searchRecordEntity);
        log.info("搜索记录id:{}添加数据缓存",searchRecordEntity.getId());
    }

    /**
     * @CacheEvict 从缓存searchRecord中删除key为id的数据
     * @param id
     */
    @CacheEvict(value = "searchRecord",key = "#id")
    public void remove(Integer id){
        this.removeById(id);
        log.info("搜索记录id:{}移除数据缓存",id);
    }

    /**
     *  @Cacheable 缓存key为searchRecord的id数据到缓存searchRecord中
     * @param id
     * @return
     */
    @Cacheable(value = "searchRecord",key = "#id")
    public SearchRecordEntity findById(Integer id){
        SearchRecordEntity searchRecordEntity = this.getById(id);
        log.info("搜索记录id:{}查看数据缓存",searchRecordEntity.getId());
        return searchRecordEntity;
    }


}

3.controller层

package com.demo.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.R;
import com.demo.dto.SearchRecordRequest;
import com.demo.entity.SearchRecordEntity;
import com.demo.service.SearchRecordService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * SearchRecordController
 *
 * @Description
 */
@Slf4j
@RestController
@RequestMapping(value = "esp/search-record")
public class SearchRecordController {

    @Resource
    private SearchRecordService searchRecordService;

    /**
     * 查询搜索记录列表接口
     *
     * @param recordRequest
     * @return
     */
    @GetMapping("/findAll")
    public R<IPage<SearchRecordEntity>> findAll(SearchRecordRequest recordRequest) {
        try {
            if (recordRequest.getPage() == null || recordRequest.getPageSize() == null) {
                return R.failed("page或pageSize不能为空");
            }
            return R.ok(searchRecordService.findAll(recordRequest));

        } catch (Exception e) {
            log.error("查询搜索记录列表接口异常:{}", e);
            return R.failed("查询搜索记录列表接口异常:" + e.getMessage());
        }
    }

    @GetMapping("find/{id}")
    public R<SearchRecordEntity> findById(@PathVariable Integer id) {
        return R.ok(searchRecordService.findById(id));
    }

    @GetMapping("save")
    public R<String> save(SearchRecordEntity searchRecordEntity) {
        searchRecordService.saveSearchRecord(searchRecordEntity);
        return R.ok("ok");
    }
    @GetMapping("remove/{id}")
    public R<String> removeById(@PathVariable Integer id) {
        searchRecordService.remove(id);
        return R.ok("ok");
    }
}

4.测试

(1)测试@Cacheable

首次访问http://localhost:8090/esp/search-record/find/7

Springboot的cache缓存机制  

再次访问  http://localhost:8090/esp/search-record/find/7 无日志打印,数据仍然返回,说了直接查询缓存数据

Springboot的cache缓存机制

(2)测试 @CacheEvict

访问:http://localhost:8090/esp/search-record/remove/7 删除了缓存

Springboot的cache缓存机制

 (3)测试 @CachePut

访问:http://localhost:8090/esp/search-record/save?id=13&name=汽车业务&remark=汽车品牌

Springboot的cache缓存机制

版权声明:程序员胖胖胖虎阿 发表于 2022年11月22日 上午7:48。
转载请注明:Springboot的cache缓存机制 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...