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.測試
呼叫使用快取的地方,一般是從前端發起請求;
初次請求,從資料庫拿資料;
清空控制檯,現在來二次請求;
已經不再從資料庫獲取資料
清空控制檯,仙子,我們來呼叫清空快取操作:
快取清理成功
此時,我們發起第三次觸發快取的請求
從資料庫讀取,這就證明了咱們的程式碼生效了,搞定。
寫在最後
哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!