1. 程式人生 > 實用技巧 >Spring,SpringBoot 啟用快取、禁用快取實現隨意切換

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: [email protected]
 */
@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.測試

  呼叫使用快取的地方,一般是從前端發起請求;

  初次請求,從資料庫拿資料;

  清空控制檯,現在來二次請求;

  已經不再從資料庫獲取資料

  清空控制檯,仙子,我們來呼叫清空快取操作:

  快取清理成功

  此時,我們發起第三次觸發快取的請求

  從資料庫讀取,這就證明了咱們的程式碼生效了,搞定。

寫在最後

  哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!

相關推薦: