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 

 

写在最后

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

 相关推荐:

 

posted @ 2020-12-16 19:56  Marydon  阅读(4798)  评论(0编辑  收藏  举报