SpringBoot中cache使用的實(shí)現(xiàn)示例
前言
對(duì)于SpringBoot的Cache,其實(shí)已經(jīng)有很多文章對(duì)使用說(shuō)明、底層詳解等各個(gè)角度進(jìn)行了講解。
本文則會(huì)結(jié)合更加詳細(xì)的使用場(chǎng)景,對(duì)cache的存儲(chǔ)和查詢邏輯進(jìn)行說(shuō)明。
緩存的增刪改查
查詢數(shù)據(jù)列表
先看一段代碼
@Cacheable(value = "devices")
public Set<Integer> getAllDeviceId() {
LambdaQueryWrapper<DevicePo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DevicePo::getIsDelete,false);
List<DevicePo> devicePos = deviceMapper.selectList(queryWrapper);
if(CollectionUtils.isEmpty(devicePos)){
return Collections.emptyList();
}
Set<Integer> deviceIds = devicePos.stream().collect(Collectors.toMap(DevicePo::getDeviceId, DevicePo::getDeviceName)).keySet();
return deviceIds;
}
使用@Cacheable可以讀取數(shù)據(jù)并存儲(chǔ)到緩存中,這比較好理解。 在這里value則是代表了一個(gè)緩存池(請(qǐng)?jiān)试S我暫時(shí)先這么叫),表示從數(shù)據(jù)庫(kù)查詢出的數(shù)據(jù)會(huì)保存到名為devices的緩存池中。
在下次調(diào)用時(shí),則會(huì)先檢測(cè)緩存池devices中是否有數(shù)據(jù),如果有數(shù)據(jù),就直接返回,沒(méi)有數(shù)據(jù)就執(zhí)行方法,產(chǎn)生新的數(shù)據(jù)。
為什么返回的是id集合?而不是數(shù)據(jù)集合?
在還沒(méi)有講到新增和刪除緩存數(shù)據(jù)時(shí),可以理解為,是為了節(jié)省內(nèi)存的占用。
如果緩存的是數(shù)據(jù)集合,當(dāng)有一個(gè)【根據(jù)id獲取數(shù)據(jù)的方法時(shí)】就會(huì)造成內(nèi)存中緩存了兩份數(shù)據(jù),這無(wú)疑造成了緩存的浪費(fèi)。
本質(zhì)上,你可以理解,在緩存數(shù)據(jù)集合和單條數(shù)據(jù)時(shí),其實(shí)并沒(méi)有共用一塊數(shù)據(jù)內(nèi)存。只是非常關(guān)鍵的一個(gè)概念,千萬(wàn)不要誤認(rèn)為數(shù)據(jù)集合和單條數(shù)據(jù)共用一塊數(shù)據(jù)內(nèi)存。
查詢單個(gè)數(shù)據(jù)
@Cacheable(value = "devices", key = "#id")
public DevicePo getById(Integer id) {
if (id == null) {
return null;
}
return deviceMapper.selectById(id);
}
相比于【獲取數(shù)據(jù)集合】,單條數(shù)據(jù)多了請(qǐng)求參數(shù),在@Cacheable注解中也多了key,雖然value都是devices,如果還是以【緩存池】來(lái)代表value的話,表面看【查詢所有數(shù)據(jù)集合方法】和【獲取單條數(shù)據(jù)】的@Cacheable注解value都為devices,好像共用了一個(gè)緩存池,而key則會(huì)被誤認(rèn)為是從【緩存池】中在數(shù)據(jù)集合中進(jìn)行了過(guò)濾,這也可能會(huì)讓人為認(rèn)為它們的數(shù)據(jù)地址也是相同的。
其實(shí),共用【緩存池】這么說(shuō)也沒(méi)毛病,key作為過(guò)濾也沒(méi)毛病,但最后的結(jié)論是錯(cuò)的。
其實(shí)springBoot的cache緩存,你可以理解為是兩層嵌套的map,即Map<String,Map<String,Object>,map的key1為@Cacheable的value,key2為@Cacheable的key。
那【獲取數(shù)據(jù)集合方法】和【獲取單個(gè)數(shù)據(jù)方法】在這個(gè)map的存儲(chǔ)就變?yōu)榱耍?br />【獲取數(shù)據(jù)集合方法】: map.get("devices").put("all", list);
【獲取單個(gè)數(shù)據(jù)方法】: map.get("devices").put("1", obj); //假設(shè)數(shù)據(jù)id為1
到這里,在新增、修改、刪除時(shí),如果你還是一味的只是更新單條數(shù)據(jù)緩存,就會(huì)發(fā)現(xiàn)【獲取數(shù)據(jù)集合方法】為什么沒(méi)有更新了吧。
新增一條新的數(shù)據(jù)
@CachePut(value = "devices", key = "#result.id")這是一個(gè)很標(biāo)準(zhǔn)的新增數(shù)據(jù)的注解。但是這里面會(huì)有兩個(gè)問(wèn)題。
首先,可能很多文章會(huì)這么寫:
@CachePut(value = "devices", key = "#device.id")
public Device add(Device device) {
...
}
這本身沒(méi)毛病,但是,你的請(qǐng)求參數(shù)中有id么? 我猜肯定沒(méi)有。那我換種寫法:
/**
* @return 返回設(shè)備id
*/
@CachePut(value = "devices", key = "#device.id")
public int add(Device device) {
...
}
如果返回的是數(shù)據(jù)id,或者boolean類型呢?寫入緩存的會(huì)是什么?還會(huì)是數(shù)據(jù)實(shí)體么?肯定不是,并且還會(huì)暴露上面那個(gè)問(wèn)題,device中沒(méi)有id。
那為什么第一種寫法沒(méi)有問(wèn)題? 你共用一個(gè)device實(shí)體,在填充id時(shí),請(qǐng)求參數(shù)中的id已經(jīng)被填充了。如果你的請(qǐng)求參數(shù)與返回的device不同,這個(gè)緩存也就不會(huì)保存,因?yàn)檎?qǐng)求參數(shù)的id為null,key為null不會(huì)保存到緩存。
第二個(gè)問(wèn)題,則是結(jié)合上面的查詢,如果你也有【獲取所有數(shù)據(jù)集合方法】,那這種寫法一定不會(huì)更新所有數(shù)據(jù)集合的緩存。
我們換種寫法:
@Caching(evict = {
@CacheEvict(value = "devices", allEntries = true),
@CacheEvict(value = "devices", key = "#result")
})
public int add(Device device) {
...
}
使用@Caching來(lái)處理,一個(gè)是刪除所有數(shù)據(jù)集合緩存,一個(gè)是刪除單條數(shù)據(jù)緩存,單條數(shù)據(jù)緩存的key則是用返回值(如果你的返回值是實(shí)體本身,也可以用put代替)
這樣在下次調(diào)用查詢接口時(shí),就會(huì)重新生成緩存。
更新一條數(shù)據(jù)
邏輯與新增相同,這里就不再贅述
刪除一條數(shù)據(jù)
邏輯與新增相同,這里就不再贅述
到此這篇關(guān)于SpringBoot中cache使用的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot cache使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 使用POI生成帶聯(lián)動(dòng)下拉框的excel表格實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家分享Java 使用POI生成帶聯(lián)動(dòng)下拉框的excel表格,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-09-09
IDEA創(chuàng)建Spring項(xiàng)目無(wú)法選擇Java8的問(wèn)題及解決
文章描述了在使用Spring創(chuàng)建項(xiàng)目時(shí)遇到的問(wèn)題,通過(guò)將服務(wù)器地址從https://start.spring.io/替換為https://start.aliyun.com/,成功解決了無(wú)法選擇Java8的問(wèn)題2025-01-01
Java 異步線程監(jiān)聽與結(jié)果回調(diào)及異常捕獲總結(jié)分析
異常是程序之中導(dǎo)致程序中斷的一種指令流,異常一旦出現(xiàn)并且沒(méi)有進(jìn)行合理處理的話,那么程序就將中斷執(zhí)行,這篇文章綜合介紹了異步線程監(jiān)聽與結(jié)果回調(diào)及異常捕獲2021-11-11
springMVC?MultipartFile上傳圖片時(shí)如何修改圖片大小
這篇文章主要介紹了springMVC?MultipartFile上傳圖片時(shí)如何修改圖片大小問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
Java中LinkedList數(shù)據(jù)結(jié)構(gòu)的詳細(xì)介紹
這篇文章主要介紹了Java中LinkedList,Linked List 是 java.util 包中 Collection 框架的一部分,文中提供了詳細(xì)的代碼說(shuō)明,需要的朋友可以參考下2023-05-05

