Spring緩存注解@Cacheable @CacheEvit @CachePut使用介紹
Spring在3.1版本,就提供了一條基于注解的緩存策略,實(shí)際使用起來還是很絲滑的,本文將針對(duì)幾個(gè)常用的注解進(jìn)行簡(jiǎn)單的介紹說明,有需要的小伙伴可以嘗試一下
本文主要知識(shí)點(diǎn):
- @Cacheable: 緩存存在,則使用緩存;不存在,則執(zhí)行方法,并將結(jié)果塞入緩存
- @CacheEvit: 失效緩存
- @CachePut: 更新緩存
I. 項(xiàng)目環(huán)境
1. 項(xiàng)目依賴
本項(xiàng)目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA + redis5.0進(jìn)行開發(fā)
開一個(gè)web服務(wù)用于測(cè)試
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>
全程使用默認(rèn)配置,redis本機(jī),端口6379,無密碼
II. 緩存注解介紹
1. @Cacheable
這個(gè)注解用于修飾方法or類,當(dāng)我們?cè)L問它修飾的方法時(shí),優(yōu)先從緩存中獲取,若緩存中存在,則直接獲取緩存的值;緩存不存在時(shí),執(zhí)行方法,并將結(jié)果寫入緩存
這個(gè)注解,有兩個(gè)比較核心的設(shè)置
/** * 與 cacheNames 效果等價(jià) */ @AliasFor("cacheNames") String[] value() default {}; @AliasFor("value") String[] cacheNames() default {}; /** * 緩存key */ String key() default "";
cacheNames可以理解為緩存key的前綴,可以為組件緩存的key變量;當(dāng)key不設(shè)置時(shí),使用方法參數(shù)來初始化,注意key為SpEL表達(dá)式,因此如果要寫字符串時(shí),用單引號(hào)括起來
一個(gè)簡(jiǎn)單的使用姿勢(shì)
/** * 首先從緩存中查,查到之后,直接返回緩存數(shù)據(jù);否則執(zhí)行方法,并將結(jié)果緩存 * <p> * redisKey: cacheNames + key 組合而成 --> 支持SpEL * redisValue: 返回結(jié)果 * * @param name * @return */ @Cacheable(cacheNames = "say", key = "'p_'+ #name") public String sayHello(String name) { return "hello+" + name + "-->" + UUID.randomUUID().toString(); }
如我們傳參為 yihuihui, 那么緩存key為 say::p_yihuihui
除了上面三個(gè)配置值之外,查看@Cacheable注解源碼的童鞋可以看到還有condition設(shè)置,這個(gè)表示當(dāng)它設(shè)置的條件達(dá)成時(shí),才寫入緩存
/** * 滿足condition條件的才寫入緩存 * * @param age * @return */ @Cacheable(cacheNames = "condition", key = "#age", condition = "#age % 2 == 0") public String setByCondition(int age) { return "condition:" + age + "-->" + UUID.randomUUID().toString(); }
上面這個(gè)case中,age為偶數(shù)的時(shí)候,才走緩存;否則不寫緩存
接下來是unless參數(shù),從名字上可以看出它表示不滿足條件時(shí)才寫入緩存
/** * unless, 不滿足條件才寫入緩存 * * @param age * @return */ @Cacheable(cacheNames = "unless", key = "#age", unless = "#age % 2 == 0") public String setUnless(int age) { return "unless:" + age + "-->" + UUID.randomUUID().toString(); }
2. @CachePut
不管緩存有沒有,都將方法的返回結(jié)果寫入緩存;適用于緩存更新
/** * 不管緩存有沒有,都寫入緩存 * * @param age * @return */ @CachePut(cacheNames = "t4", key = "#age") public String cachePut(int age) { return "t4:" + age + "-->" + UUID.randomUUID().toString(); }
3. @CacheEvict
這個(gè)就是我們理解的刪除緩存
/** * 失效緩存 * * @param name * @return */ @CacheEvict(cacheNames = "say", key = "'p_'+ #name") public String evict(String name) { return "evict+" + name + "-->" + UUID.randomUUID().toString(); }
4. @Caching
在實(shí)際的工作中,經(jīng)常會(huì)遇到一個(gè)數(shù)據(jù)變動(dòng),更新多個(gè)緩存的場(chǎng)景,對(duì)于這個(gè)場(chǎng)景,可以通過@Caching來實(shí)現(xiàn)
/** * caching實(shí)現(xiàn)組合,添加緩存,并失效其他的緩存 * * @param age * @return */ @Caching(cacheable = @Cacheable(cacheNames = "caching", key = "#age"), evict = @CacheEvict(cacheNames = "t4", key = "#age")) public String caching(int age) { return "caching: " + age + "-->" + UUID.randomUUID().toString(); }
上面這個(gè)就是組合操作
- 從 caching::age緩存取數(shù)據(jù),不存在時(shí)執(zhí)行方法并寫入緩存;
- 失效緩存 t4::age
5. 異常時(shí),緩存會(huì)怎樣?
上面的幾個(gè)case,都是正常的場(chǎng)景,當(dāng)方法拋出異常時(shí),這個(gè)緩存表現(xiàn)會(huì)怎樣?
/** * 用于測(cè)試異常時(shí),是否會(huì)寫入緩存 * * @param age * @return */ @Cacheable(cacheNames = "exception", key = "#age") @Cacheable(cacheNames = "say", key = "'p_yihuihui'") public int exception(int age) { return 10 / age; }
根據(jù)實(shí)測(cè)結(jié)果,當(dāng)age==0時(shí),上面兩個(gè)緩存都不會(huì)成功
6. 測(cè)試用例
接下來驗(yàn)證下緩存注解與上面描述的是否一致
@RestController public class IndexRest { @Autowired private BasicDemo helloService; @GetMapping(path = {"", "/"}) public String hello(String name) { return helloService.sayHello(name); } }
上面這個(gè)主要是驗(yàn)證@Cacheable注解,若緩存不命中,每次返回的結(jié)果應(yīng)該都不一樣,然而實(shí)際訪問時(shí),會(huì)發(fā)現(xiàn)返回的都是相同的
curl http://localhost:8080/?name=yihuihui
失效緩存
@GetMapping(path = "evict") public String evict(String name) { return helloService.evict(String.valueOf(name)); }
失效緩存,需要和上面的case配合起來使用
curl http://localhost:8080/evict?name=yihuihui curl http://localhost:8080/?name=yihuihui
剩下其他的相關(guān)測(cè)試類就比較好理解了,一并貼出對(duì)應(yīng)的代碼
@GetMapping(path = "condition") public String t1(int age) { return helloService.setByCondition(age); } @GetMapping(path = "unless") public String t2(int age) { return helloService.setUnless(age); } @GetMapping(path = "exception") public String exception(int age) { try { return String.valueOf(helloService.exception(age)); } catch (Exception e) { return e.getMessage(); } } @GetMapping(path = "cachePut") public String cachePut(int age) { return helloService.cachePut(age); }
7. 小結(jié)
最后管理小結(jié)一下Spring提供的幾個(gè)緩存注解
- @Cacheable: 緩存存在,則從緩存取;否則執(zhí)行方法,并將返回結(jié)果寫入緩存
- @CacheEvit: 失效緩存
- @CachePut: 更新緩存
- @Caching: 都注解組合
上面雖說可以滿足常見的緩存使用場(chǎng)景,但是有一個(gè)非常重要的點(diǎn)沒有說明,緩存失效時(shí)間應(yīng)該怎么設(shè)置???
如何給每個(gè)緩存設(shè)置不同的緩存失效時(shí)間,咱么下篇博文見,我是一灰灰,歡迎關(guān)注長(zhǎng)草的公眾號(hào)一灰灰blog
III. 不能錯(cuò)過的源碼和相關(guān)知識(shí)點(diǎn)
0. 項(xiàng)目
工程:https://github.com/liuyueyi/spring-boot-demo
源碼:https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/125-cache-ano
到此這篇關(guān)于Spring緩存注解@Cacheable @CacheEvit @CachePut使用介紹的文章就介紹到這了,更多相關(guān)Spring @Cacheable @CacheEvit @CachePut內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Java Servlet生成動(dòng)態(tài)二維碼的實(shí)現(xiàn)步驟
在現(xiàn)代互聯(lián)網(wǎng)時(shí)代,二維碼廣泛應(yīng)用于各個(gè)領(lǐng)域,包括支付、認(rèn)證、信息傳遞等,在Web開發(fā)中,通過Java Servlet生成動(dòng)態(tài)二維碼是一個(gè)常見的需求,本文將介紹如何使用Java Servlet結(jié)合Google的ZXing庫(kù)生成動(dòng)態(tài)二維碼,需要的朋友可以參考下2023-11-11Maven里面沒有plugins dependence問題解決
在整合Nacos和Dubbo時(shí),出現(xiàn)Maven錯(cuò)誤可以通過檢查父模塊的依賴解決,問題源于MySQL驅(qū)動(dòng)版本不兼容,移除特定依賴并刷新pom文件可恢復(fù)項(xiàng)目,執(zhí)行clean命令,查看報(bào)錯(cuò),感興趣的可以了解一下2024-10-10Java實(shí)現(xiàn)批量發(fā)送帶附件的郵件代碼
大家好,本篇文章主要講的是Java實(shí)現(xiàn)批量發(fā)送帶附件的郵件代碼,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01關(guān)于Controller 層返回值的公共包裝類的問題
本文給大家介紹Controller 層返回值的公共包裝類-避免每次都包裝一次返回-InitializingBean增強(qiáng),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-09-09Mybatis SQL日志如何轉(zhuǎn)換為可執(zhí)行sql
這篇文章主要介紹了Mybatis SQL日志如何轉(zhuǎn)換為可執(zhí)行sql問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09