• Spring,SpringBoot 启用缓存、禁用缓存实现随意切换


    1.情景展示

      在实际开发过程中,我们为了减少对数据库的频繁访问,会把不易更改的数据放到缓存中,减少对数据库的访问,以此,既能减少数据库的操作次数,也能节省响应时间;

      但是,缓存同样是一把双刃剑,也会给我们带来不便,比如:

      对于后端开发人员来说,我们习惯于直接操作数据库完成对数据库的修改,而不是通过前端发起请求,这样,就会导致一个问题:

      不会触发缓存更新操作,数据库虽然已经改好,但是,缓存没有得到更新;

      或者是,有的项目根本就不涉及修改操作,只负责读取数据,这就不存在更新缓存的情形;

      而一旦数据库发生修改,就无法保持数据同步,这就非常尴尬了,怎么办?

    2.情况分析

      我们通常使用的缓存注解是@CacheEnable,该注解只在第一次请求时会从数据库拿到数据,并放到缓存当中,后续请求将直接从缓存读取;

      鉴于spring启用缓存,是通过使用注解@EnableCaching来完成的,我脑海里首先想到的是:

      能不能在配置文件中进行动态设置,换言之就是:将是否启动缓存的决定权迁移到配置文件中,比如:application.yml中。

      事实证明,我想太多了,无法实现!

    3.解决方案

      我们知道,spring的缓存只存在于项目运行期间,它不像redis,即使你把项目停了,缓存依然会存在;

      由此,就诞生了第一种解决方案:

      方案一:重启项目 

      重启项目,所有的缓存将不复存在。

      方案二:禁用缓存

      我们只要把使用注解@EnableCaching删掉或者是注销掉,重启项目就OK啦。

      但是,这对于已经部署在Linux服务器下的项目而言,可操作性不强,我们还得替换class文件才行。

      方案三:手动触发清除缓存操作

      可能,会有小伙伴说,设置缓存的失效时间不就完了,可以设置失效时间,但那是只有到指定时间后才会失效,不能满足我们的及时性,总不能一直等到缓存失效,再干活吧? 

      我们可以创建控制器,向外提供接口,手动清除缓存,通过这种方式来间接实现缓存的清除操作,这样,也不用重启服务器,缓存也能接着用(重启服务器的目的就是为了清除缓存)

    import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
    import com.github.xiaoymin.knife4j.annotations.ApiSupport;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.annotations.ApiParam;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cache.Cache;
    import org.springframework.cache.CacheManager;
    import org.springframework.stereotype.Controller;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import javax.annotation.Resource;
    import javax.validation.constraints.NotBlank;
    
    /**
     * 清除缓存控制器
     * @description:
     * @author: Marydon
     * @date: 2020-12-16 12:51
     * @version: 1.0
     * @email: marydon20170307@163.com
     */
    @Api("CacheController")
    @ApiSupport(order = 266, author = "Marydon")
    @Slf4j
    // 必须作用在类上,不然只能校验Null,不能校验Empty
    @Validated
    @Controller
    public class CacheController {
    
        // 注入缓存管理器
        @Resource
        private CacheManager cacheManager;
    
        @ApiOperation(value = "清除所有缓存", notes = "清空所有缓存")
        @ApiOperationSupport(author = "Marydon", order = 1)
        @GetMapping("/clearAll")
        public String clearAllCache() {
            cacheManager.getCacheNames().forEach(cacheName -> {
                cacheManager.getCache(cacheName).clear();
                log.info("缓存".concat(cacheName).concat("清理成功!"));
            });
    
            return "所有缓存清理完毕";
        }
    
        @ApiOperation(value = "清除指定缓存", notes = "根据入参清除缓存")
        @ApiOperationSupport(author = "Marydon", order = 10)
        // knife4j会将headers的值识别为响应数据类型
        @RequestMapping(value = "clear", method = {RequestMethod.GET, RequestMethod.POST}, headers = {"Accept=text/pain"})
        // 入参需要使用@RequestParam,否则请求会被spring拦截,进不来(请求数据类型为空)
        public String clearCacheByName(@ApiParam(value = "缓存名称", required = true, example = "aaCache") @RequestParam @NotBlank(message = "缓存名称不能为空") String cacheName) {
            Cache cache = cacheManager.getCache(cacheName);
            if (null == cache) return cacheName + "并不存在";
    
            cache.clear();
            log.info(cacheName + "缓存清理完毕");
            return cacheName + "缓存清理完毕";
        }
    }
    

      上面提供了两种清除缓存的方法,一种是清除所有缓存,另一种是清除指定缓存。  

    4.测试

      调用使用缓存的地方,一般是从前端发起请求;

      初次请求,从数据库拿数据;

      清空控制台,现在来二次请求;

      已经不再从数据库获取数据 

      清空控制台,仙子,我们来调用清空缓存操作:

      缓存清理成功

      此时,我们发起第三次触发缓存的请求

      从数据库读取,这就证明了咱们的代码生效了,搞定。 

    5.bug修复

      2020-12-17

      上面的代码存在一个问题:我们实际想返回字符串信息,但是实际上,springmvc会自动将字符串识别为路径,这就非常尴尬,返回的就是404;

      如何让springmvc不把它当成路径,而是作为数据返回呢?

      这里提供三种实现方式:

      最古老的方式:返回字符流

      第二种:将@Controller替换成@RestController

      第三种:在接口方法上添加@ResponseBody 

    写在最后

      哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

     相关推荐:

  • 相关阅读:
    区间树
    最大流
    单源最短路径
    散列表
    最小生成树
    软件体系结构2
    软件体系结构
    Leetcode 687.最长同值路径
    Leetcode 686.重复叠加字符串匹配
    Python测试框架
  • 原文地址:https://www.cnblogs.com/Marydon20170307/p/14143175.html
Copyright © 2020-2023  润新知