@[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的緩存注解的理解。如果有什么不對的冗疮,歡迎大家指出萄唇,謝謝??。