小白教你完全理解 spring 緩存 @Cacheable、@CachePut豆拨、@CacheEvict搂蜓、@Caching

@[TOC]

概述

我們在開發(fā)的過程中可能會遇到一些請求比較頻繁。但是請求的結(jié)果有==基本是不會變化的==(或者是不會變化的)辽装。

而我們每次都要經(jīng)過運算或者是去數(shù)據(jù)庫中查找結(jié)果帮碰。這就回導(dǎo)致我們這個接口的效率十分的低下。

那對于這種接口我們就可以請求的時候先看下緩存中又沒有保存上一次的結(jié)果拾积,如果有就直接返回殉挽。

沒有就如運算或者去數(shù)據(jù)庫中找。然后存入緩存中就可以了拓巧。這樣后面的請求就可以直接從緩存中得到結(jié)果了斯碌。效率自然就上去了。


示例圖

而 spring 的緩存注解就是為我們提供了這些方法肛度。

@Cacheable傻唾、@CachePut、@CacheEvict承耿、@Caching冠骄。

下面我們來看下如何使用吧。

==ps:本文所有的演示均以redis作為緩存==

@Cacheable 和 @CachePut

==@Cacheable== 表明spring在調(diào)用方法之前會先去緩存中查找又沒有之前這個方法的返回值加袋。如果有就直接返回緩存凛辣,沒有則調(diào)用方法,然后將返回值放入緩存之中职烧。

==@CachePut== Spring會將該方法的結(jié)果直接放入緩存之中扁誓。

兩者的區(qū)別

@Cacheable和@CachePut都是填充緩存唯一的不同就是@Cacheable會在調(diào)用方法之前檢查緩存,而@CachePut則不會蚀之。

@Cacheable和@CachePut有都有一些屬性蝗敢。他們共有的屬性如下圖

屬性描述

屬性 類型 描述
value String[] 緩存的名稱
condition String SpEL表達式,如果是false則不會將緩存應(yīng)用到方法調(diào)用上
key String SpEL表達式足删,緩存的KEY
unless String SpEL表達式寿谴,如果是false則不會將方法的返回值存儲到緩存上

舉例

假設(shè)我們目前要寫一個獲取用戶個人信息的接口,而這個人的個人信息又不是會經(jīng)常變化壹堰。但是每次進入商城我們都要獲取一遍拭卿。如果不用緩存那么我們每次都需要去數(shù)據(jù)庫查詢一遍。效率就不高贱纠。那我們就可以修改成緩存峻厚。

// userInfo 為緩存的名稱 userId為key,為了區(qū)分不同人的信息
@Cacheable(value = "userInfo", key = "#userId")
    public User getUser(Long userId) {
        // 模擬數(shù)據(jù)庫查找
        User user=get(userId);
        return user;
    }

一下就是我們第一次調(diào)用這個方法谆焊,方法會把返回值存入緩存中惠桃。下一次請求就直接會調(diào)取緩存中的方法。而不會再去查詢辖试。


在這里插入圖片描述

我們再插入一條


在這里插入圖片描述

而使用 ==@CachePut== 則會直接調(diào)用方法然后將返回值直接更新的緩存中辜王。比如我們的userInfo改變了,需要將新的緩存放入其中 罐孝,那么就可以使用以下代碼
  @CachePut(value = "userInfo", key = "#userId == -1")
    public User updateUserInfoCache(Long userId,Boolean) {
        // 模擬數(shù)據(jù)庫查找
        User user=get(userId);
        return user;
    }

會直接查詢出userInfo信息然后更新到緩存呐馆。

自定義緩存key

@Cacheable和@CachePut都帶有key屬性。key屬性可以使用任何SpEL表達式莲兢,但是大部分的時候我們會定義與值相關(guān)的汹来,用于區(qū)分之后可以找到值,比如userInfo的Id

在為編寫SpEL表達式的時候spring暴露出一些可以使用的元數(shù)據(jù)改艇,如下表所示

表達式 描述
#root.args 傳遞給緩存的參數(shù)收班,形式為數(shù)組
#root.caches 該方法執(zhí)行時所對應(yīng)的緩存,形式為數(shù)組
#root.target 目標(biāo)對象
#root.targetClass 目標(biāo)對象的類谒兄,是 #root.target.class 的縮寫
#root.method 緩存方法
#root.methodName 緩存方法的名稱摔桦,是 #root.method.name 的縮寫
#result 方法調(diào)用的返回值(@Cacheable不可以使用)
#Argument Argument可替換成任意方法參數(shù)名(如#userId)或者參數(shù)索引(如 #a0、#p0)

我們下面來舉個例子來看下下面這些具體代表什么承疲。

    //  #root.args = [value,value2]
    //  #root.caches[0].getName = testCache
    //  #root.target = 當(dāng)前對象 TestCache
    //  #root.targetClass = 當(dāng)前對象類 TestCache
    //  #root.method = 當(dāng)前方法 putCache
    //  #root.methodName = 當(dāng)前方法名 putCache
    //  #result = 當(dāng)前方法的返回值 resultInt
    //  #value(#Argument替換) = 方法參數(shù)value
    @CachePut(value = "testCache", key="#value")
    public Integer putCache(int value,int value2){
       int resultInt = value+1;
       return resultInt;
    }

這里我們一般可以使用方法的參數(shù)作為緩存的key邻耕。或者是返回值作為key(如 #result.id )燕鸽。

條件緩存

@Cacheable 和 @CachePut 的==unless==和==condition==屬性可以實現(xiàn)條件化緩存赊豌。

如果unless屬性的SpEL的值返回結(jié)果為true。那么方法的返回值不會放到緩存中绵咱。
如果condition屬性的SpEL的值返回結(jié)果為false,那么方法緩存就會被禁用碘饼。

表面上看來兩者的作用是一樣的。但是其實是有一點差別的悲伶。

==unless==如果為true艾恼,那么會緩存方法的返回值不會放入緩存,但是依然會去緩存中查找又沒有匹配的值麸锉。如果有則會返回钠绍。
==condition==如果為false,那么緩存的方法返回值不會放入緩存花沉,也不會去緩存中查找匹配的值柳爽。

下面我們用兩個例子來驗證以下

我們首先使用下面的方法將一個值放入緩存

    @CachePut(value = "testCache", key="#root.targetClass.getSimpleName()")
    public String putCache(){
        return "這是緩存的值";
    }

這時我們的緩存中會有一個值媳握。


在這里插入圖片描述

==unless==

    @Cacheable(value = "testCache", key="#root.targetClass.getSimpleName()", unless = "#value==10")
    public String putCacheUnless(int value){
        System.out.println("執(zhí)行了方法");
        return "保存成功了";
    }

測試

System.out.println(testCache.putCacheUnless(10));

返回值如下圖,我們可以看出uless為true磷脯,此時回去查找緩存中又沒有匹配的值蛾找,而我們緩存中正好有值,所以直接返回了赵誓。


在這里插入圖片描述

如果我們把緩存刪除打毛。然后再次調(diào)用,那么結(jié)果如下俩功。我們可以看到此時執(zhí)行了方法幻枉。然后把方法的返回值返回了。


在這里插入圖片描述

==condition==

    @Cacheable(value = "testCache", key="#root.targetClass.getSimpleName()", condition = "#value!=10")
    public String putCacheCondition(int value){
        System.out.println("執(zhí)行了方法");
        return "保存成功了";
    }

測試

System.out.println(testCache.putCacheCondition(10));

此時結(jié)果如下诡蜓。此時雖然緩存中有匹配的值熬甫,但是還是執(zhí)行了方法,并返回了方法的返回值蔓罚。


在這里插入圖片描述

如果我們把緩存刪除了罗珍,結(jié)果如下,我們可以看到結(jié)果沒有發(fā)生變化可以看出==condition不管緩存中又沒有匹配的值都不會去緩存中查找脚粟。==


在這里插入圖片描述

@CacheEvict

==@CacheEvict== 并不會往緩存中放入任何東西覆旱。而是會從緩存中刪除指定的緩存。一般當(dāng)緩存不再有效的時候會調(diào)取此方法然后刪除核无。

屬性描述

屬性 類型 描述
value String[] 緩存的名稱
condition String SpEL表達式扣唱,如果是false則不會將緩存應(yīng)用到方法調(diào)用上
key String SpEL表達式,緩存的KEY
allEntries boolean 如果為true的話团南,無視key噪沙,會刪除當(dāng)前緩存下的所有緩存
beforeInvocation boolean 如果為true的話,會先刪除緩存再執(zhí)行方法吐根,如果為false的話正歼,會先執(zhí)行方法再刪除緩存

結(jié)語

==雖然緩存使用起來很方便,但是使用的時候要注意保證緩存的有效性拷橘。(在數(shù)據(jù)庫更新的時候要即使更新緩存)否則出現(xiàn)數(shù)據(jù)混亂問題局义。==

以上就是我對spring的緩存注解的理解。如果有什么不對的冗疮,歡迎大家指出萄唇,謝謝??。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末术幔,一起剝皮案震驚了整個濱河市另萤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖四敞,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泛源,死亡現(xiàn)場離奇詭異,居然都是意外死亡忿危,警方通過查閱死者的電腦和手機达箍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來癌蚁,“玉大人幻梯,你說我怎么就攤上這事兜畸∨停” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵咬摇,是天一觀的道長伐蒂。 經(jīng)常有香客問我,道長肛鹏,這世上最難降的妖魔是什么逸邦? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮在扰,結(jié)果婚禮上缕减,老公的妹妹穿的比我還像新娘。我一直安慰自己芒珠,他們只是感情好桥狡,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著皱卓,像睡著了一般裹芝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娜汁,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天嫂易,我揣著相機與錄音,去河邊找鬼掐禁。 笑死怜械,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的傅事。 我是一名探鬼主播宫盔,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼享完!你這毒婦竟也來了灼芭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤般又,失蹤者是張志新(化名)和其女友劉穎彼绷,沒想到半個月后巍佑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡寄悯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年萤衰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猜旬。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡脆栋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出洒擦,到底是詐尸還是另有隱情椿争,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布熟嫩,位于F島的核電站秦踪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏掸茅。R本人自食惡果不足惜椅邓,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昧狮。 院中可真熱鬧景馁,春花似錦、人聲如沸逗鸣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慕购。三九已至聊疲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沪悲,已是汗流浹背获洲。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留殿如,地道東北人贡珊。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像涉馁,于是被迫代替她去往敵國和親门岔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355