国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

做網(wǎng)站的軟件公司長尾關(guān)鍵詞挖掘愛站網(wǎng)

做網(wǎng)站的軟件公司,長尾關(guān)鍵詞挖掘愛站網(wǎng),加強(qiáng)政府網(wǎng)站的建設(shè)管理,做財(cái)務(wù)需要關(guān)注哪些網(wǎng)站大家好 , 我是蘇麟 , 今天聊一聊緩存 . 這里需要一些Redis基礎(chǔ) (可以看相關(guān)文章等) 本文章資料來自于 : 黑馬程序員 如果想要了解更詳細(xì)的資料去黑馬官網(wǎng)查看 前言:什么是緩存? 緩存,就是數(shù)據(jù)交換的 緩沖區(qū) (稱作Cache [ k? ] ),俗稱的緩存就是緩沖區(qū)內(nèi)的數(shù)據(jù),是存貯數(shù)據(jù)的…

大家好 , 我是蘇麟 , 今天聊一聊緩存 .?

這里需要一些Redis基礎(chǔ) (可以看相關(guān)文章等)

本文章資料來自于 : 黑馬程序員? 如果想要了解更詳細(xì)的資料去黑馬官網(wǎng)查看

前言:什么是緩存?

緩存,就是數(shù)據(jù)交換的?緩沖區(qū) (稱作Cache [ k?? ] ),俗稱的緩存就是緩沖區(qū)內(nèi)的數(shù)據(jù),是存貯數(shù)據(jù)的臨時地方,讀寫性能較高。一般從數(shù)據(jù)庫中獲取,存儲于本地


為什么要使用緩存

緩存的作用

  1. 速度快
  2. 降低后端負(fù)載
  3. 提高讀寫效率,降低響應(yīng)時間

緩存的成本

  1. 數(shù)據(jù)一致性成本
  2. 代碼維護(hù)成本
  3. 運(yùn)維成本

如何使用緩存

瀏覽器緩存:主要是存在于瀏覽器端的緩存

應(yīng)用層緩存:可以分為tomcat本地緩存,比如之前提到的map,或者是使用redis作為緩存

數(shù)據(jù)庫緩存:在數(shù)據(jù)庫中有一片空間是 buffer pool,增改查數(shù)據(jù)都會先加載到mysql的緩存中

CPU緩存:當(dāng)代計(jì)算機(jī)最大的問題是 cpu性能提升了,但內(nèi)存讀寫速度沒有跟上,所以為了適應(yīng)當(dāng)下的情況,增加了cpu的L1,L2,L3級的緩存


實(shí)現(xiàn)緩存

Redis簡單實(shí)現(xiàn)

沒使用緩存之前

@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {//這里是直接查詢數(shù)據(jù)庫return shopService.queryById(id);
}

?使用緩存

    @GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {String key = "cache:shop:" + id;// 1.從redis查詢商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判斷是否存在if (StrUtil.isNotBlank(shopJson)) {// 3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 4.不存在,根據(jù)id查詢數(shù)據(jù)庫Shop shop = getById(id);// 5.不存在,返回錯誤if (shop == null) {return Result.fail("店鋪不存在!");}// 6.存在,寫入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop));// 7.返回return Result.ok(shop);}

緩存流程圖?

緩存更新策略

緩存更新是redis為了節(jié)約內(nèi)存而設(shè)計(jì)出來的一個東西,主要是因?yàn)閮?nèi)存數(shù)據(jù)寶貴,當(dāng)我們向redis插入太多數(shù)據(jù),此時就可能會導(dǎo)致緩存中的數(shù)據(jù)過多,所以redis會對部分?jǐn)?shù)據(jù)進(jìn)行更新,或者把他叫為淘汰更合適。

內(nèi)存淘汰:redis自動進(jìn)行,當(dāng)redis內(nèi)存達(dá)到咱們設(shè)定的max-memery的時候,會自動觸發(fā)淘汰機(jī)制,淘汰掉一些不重要的數(shù)據(jù)(可以自己設(shè)置策略方式)

超時剔除:當(dāng)我們給redis設(shè)置了過期時間ttl之后,redis會將超時的數(shù)據(jù)進(jìn)行刪除,方便咱們繼續(xù)使用緩存

主動更新:我們可以手動調(diào)用方法把緩存刪掉,通常用于解決緩存和數(shù)據(jù)庫不一致問題

數(shù)據(jù)庫緩存不一致解決方案

由于我們的緩存的數(shù)據(jù)源來自于數(shù)據(jù)庫,而數(shù)據(jù)庫的數(shù)據(jù)是會發(fā)生變化的,因此,如果當(dāng)數(shù)據(jù)庫中數(shù)據(jù)發(fā)生變化,而緩存卻沒有同步,此時就會有一致性問題存在,其后果是:

用戶使用緩存中的過時數(shù)據(jù),就會產(chǎn)生類似多線程數(shù)據(jù)安全問題,從而影響業(yè)務(wù),產(chǎn)品口碑等;怎么解決呢?有如下幾種方案

Cache Aside Pattern 人工編碼方式:緩存調(diào)用者在更新完數(shù)據(jù)庫后再去更新緩存,也稱之為雙寫方案

Read/Write Through Pattern : 由系統(tǒng)本身完成,數(shù)據(jù)庫與緩存的問題交由系統(tǒng)本身去處理

Write Behind Caching Pattern :調(diào)用者只操作緩存,其他線程去異步處理數(shù)據(jù)庫,實(shí)現(xiàn)最終一致

數(shù)據(jù)庫和緩存不一致采用什么方案

綜合考慮使用方案一,但是方案一調(diào)用者如何處理呢?這里有幾個問題

操作緩存和數(shù)據(jù)庫時有三個問題需要考慮:

如果采用第一個方案,那么假設(shè)我們每次操作數(shù)據(jù)庫后,都操作緩存,但是中間如果沒有人查詢,那么這個更新動作實(shí)際上只有最后一次生效,中間的更新動作意義并不大,我們可以把緩存刪除,等待再次查詢時,將緩存中的數(shù)據(jù)加載出來

  • 刪除緩存還是更新緩存?

    • 更新緩存:每次更新數(shù)據(jù)庫都更新緩存,無效寫操作較多

    • 刪除緩存:更新數(shù)據(jù)庫時讓緩存失效,查詢時再更新緩存

  • 如何保證緩存與數(shù)據(jù)庫的操作的同時成功或失敗?

    • 單體系統(tǒng),將緩存與數(shù)據(jù)庫操作放在一個事務(wù)

    • 分布式系統(tǒng),利用TCC等分布式事務(wù)方案

應(yīng)該具體操作緩存還是操作數(shù)據(jù)庫,我們應(yīng)當(dāng)是先操作數(shù)據(jù)庫,再刪除緩存,原因在于,如果你選擇第一種方案,在兩個線程并發(fā)來訪問時,假設(shè)線程1先來,他先把緩存刪了,此時線程2過來,他查詢緩存數(shù)據(jù)并不存在,此時他寫入緩存,當(dāng)他寫入緩存后,線程1再執(zhí)行更新動作時,實(shí)際上寫入的就是舊的數(shù)據(jù),新的數(shù)據(jù)被舊數(shù)據(jù)覆蓋了。

  • 先操作緩存還是先操作數(shù)據(jù)庫?

    • 先刪除緩存,再操作數(shù)據(jù)庫

    • 先操作數(shù)據(jù)庫,再刪除緩存

實(shí)現(xiàn)商鋪和緩存與數(shù)據(jù)庫雙寫一致

核心思路如下:

修改ShopController中的業(yè)務(wù)邏輯,滿足下面的需求:

根據(jù)id查詢店鋪時,如果緩存未命中,則查詢數(shù)據(jù)庫,將數(shù)據(jù)庫結(jié)果寫入緩存,并設(shè)置超時時間

根據(jù)id修改店鋪時,先修改數(shù)據(jù)庫,再刪除緩存

修改重點(diǎn)代碼1:修改ShopServiceImpl的queryById方法

設(shè)置redis緩存時添加過期時間

    @GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {String key = "cache:shop:" + id;// 1.從redis查詢商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判斷是否存在if (StrUtil.isNotBlank(shopJson)) {// 3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 4.不存在,根據(jù)id查詢數(shù)據(jù)庫Shop shop = getById(id);// 5.不存在,返回錯誤if (shop == null) {return Result.fail("店鋪不存在!");}// 6.存在,寫入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);// 7.返回return Result.ok(shop);}

修改重點(diǎn)代碼2

代碼分析:通過之前的淘汰,我們確定了采用刪除策略,來解決雙寫問題,當(dāng)我們修改了數(shù)據(jù)之后,然后把緩存中的數(shù)據(jù)進(jìn)行刪除,查詢時發(fā)現(xiàn)緩存中沒有數(shù)據(jù),則會從mysql中加載最新的數(shù)據(jù),從而避免數(shù)據(jù)庫和緩存不一致的問題

    @Override@Transactionalpublic Result update(Shop shop) {Long id = shop.getId();if (id == null) {return Result.fail("店鋪id不能為空");}// 1更新數(shù)據(jù)庫updateById(shop);// 2.刪除緩存stringRedisTemplate.delete(key:CACHE_SHOP_KEY + id);return Result.ok();}

緩存穿透

緩存穿透是指客戶端請求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫中都不存在,這樣緩存永遠(yuǎn)不會生效,這些請求都會打到數(shù)據(jù)庫。

常見的解決方案有兩種:

  • 緩存空對象

    • 優(yōu)點(diǎn):實(shí)現(xiàn)簡單,維護(hù)方便

    • 缺點(diǎn):

      • 額外的內(nèi)存消耗

      • 可能造成短期的不一致

  • 布隆過濾

    • 優(yōu)點(diǎn):內(nèi)存占用較少,沒有多余key

    • 缺點(diǎn):

      • 實(shí)現(xiàn)復(fù)雜

      • 存在誤判可能?

緩存空對象思路分析:當(dāng)我們客戶端訪問不存在的數(shù)據(jù)時,先請求redis,但是此時redis中沒有數(shù)據(jù),此時會訪問到數(shù)據(jù)庫,但是數(shù)據(jù)庫中也沒有數(shù)據(jù),這個數(shù)據(jù)穿透了緩存,直擊數(shù)據(jù)庫,我們都知道數(shù)據(jù)庫能夠承載的并發(fā)不如redis這么高,如果大量的請求同時過來訪問這種不存在的數(shù)據(jù),這些請求就都會訪問到數(shù)據(jù)庫,簡單的解決方案就是哪怕這個數(shù)據(jù)在數(shù)據(jù)庫中也不存在,我們把這個數(shù)據(jù)存入到redis中去,這樣,下次用戶過來訪問這個不存在的數(shù)據(jù),那么在redis中也能找到這個數(shù)據(jù)就不會進(jìn)入到緩存了

布隆過濾:布隆過濾器其實(shí)采用的是哈希思想來解決這個問題,通過一個龐大的二進(jìn)制數(shù)組,走哈希思想去判斷當(dāng)前這個要查詢的這個數(shù)據(jù)是否存在,如果布隆過濾器判斷存在,則放行,這個請求會去訪問redis,哪怕此時redis中的數(shù)據(jù)過期了,但是數(shù)據(jù)庫中一定存在這個數(shù)據(jù),在數(shù)據(jù)庫中查詢出來這個數(shù)據(jù)后,再將其放入到redis中,

假設(shè)布隆過濾器判斷這個數(shù)據(jù)不存在,則直接返回

這種方式優(yōu)點(diǎn)在于節(jié)約內(nèi)存空間,存在誤判,誤判原因在于:布隆過濾器走的是哈希思想,只要哈希思想,就可能存在哈希沖突

編碼解決緩存穿透問題

核心思路如下:

在原來的邏輯中,我們?nèi)绻l(fā)現(xiàn)這個數(shù)據(jù)在mysql中不存在,直接就返回404了,這樣是會存在緩存穿透問題的

現(xiàn)在的邏輯中:如果這個數(shù)據(jù)不存在,我們不會返回404 ,還是會把這個數(shù)據(jù)寫入到Redis中,并且將value設(shè)置為空,歐當(dāng)再次發(fā)起查詢時,我們?nèi)绻l(fā)現(xiàn)命中之后,判斷這個value是否是null,如果是null,則是之前寫入的數(shù)據(jù),證明是緩存穿透數(shù)據(jù),如果不是,則直接返回?cái)?shù)據(jù)。

?修改代碼

    @GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {String key = "cache:shop:" + id;// 1.從redis查詢商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判斷是否存在if (StrUtil.isNotBlank(shopJson)) {// 3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//shopJson 為 "" 的時候if (shopJson != null) {return Result.ok("店鋪不存在");}// 4.不存在,根據(jù)id查詢數(shù)據(jù)庫Shop shop = getById(id);// 5.不存在,返回錯誤if (shop == null) {stringRedisTemplate.opsForValue().set(key, "",2L, TimeUnit.MINUTES);}// 6.存在,寫入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);// 7.返回return Result.ok(shop);}

小總結(jié):

緩存穿透產(chǎn)生的原因是什么?

  • 用戶請求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫中都不存在,不斷發(fā)起這樣的請求,給數(shù)據(jù)庫帶來巨大壓力

緩存穿透的解決方案有哪些?

  • 緩存null值

  • 布隆過濾

緩存雪崩

緩存雪崩是指在同一時段大量的緩存key同時失效或者Redis服務(wù)宕機(jī),導(dǎo)致大量請求到達(dá)數(shù)據(jù)庫,帶來巨大壓力。

解決方案:

  • 給不同的Key的TTL添加隨機(jī)值

    @GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {String key = "cache:shop:" + id;// 1.從redis查詢商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(key);// 2.判斷是否存在if (StrUtil.isNotBlank(shopJson)) {// 3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//shopJson 為 "" 的時候if (shopJson != null) {return Result.ok("店鋪不存在");}// 4.不存在,根據(jù)id查詢數(shù)據(jù)庫Shop shop = getById(id);// 5.不存在,返回錯誤if (shop == null) {stringRedisTemplate.opsForValue().set(key, "",(2L + new Random().nextInt(5)), TimeUnit.MINUTES);}// 6.存在,寫入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);// 7.返回return Result.ok(shop);}
  • 利用Redis集群提高服務(wù)的可用性

請看Redis集群配置的相關(guān)文章

  • 給緩存業(yè)務(wù)添加降級限流策略

這里請看SpringCloud中降極限流策略

  • 給業(yè)務(wù)添加多級緩存

這里請看SpringCloud中多級緩存的相關(guān)知識

緩存擊穿

緩存擊穿問題也叫熱點(diǎn)Key問題,就是一個被高并發(fā)訪問并且緩存重建業(yè)務(wù)較復(fù)雜的key突然失效了,無 數(shù)的請求訪問會在瞬間給數(shù)據(jù)庫帶來巨大的沖擊。

常見的解決方案有兩種:

  • 互斥鎖
  • 邏輯過期

邏輯分析:假設(shè)線程1在查詢緩存之后,本來應(yīng)該去查詢數(shù)據(jù)庫,然后把這個數(shù)據(jù)重新加載到緩存的,此 時只要線程1走完這個邏輯,其他線程就都能從緩存中加載這些數(shù)據(jù)了,但是假設(shè)在線程1沒有走完的時 候,后續(xù)的線程2,線程3,線程4同時過來訪問當(dāng)前這個方法, 那么這些線程都不能從緩存中查詢到數(shù) 據(jù),那么他們就會同一時刻來訪問查詢緩存,都沒查到,接著同一時間去訪問數(shù)據(jù)庫,同時的去執(zhí)行數(shù) 據(jù)庫代碼,對數(shù)據(jù)庫訪問壓力過大

 

解決方案一、使用鎖來解決:

因?yàn)殒i能實(shí)現(xiàn)互斥性。假設(shè)線程過來,只能一個人一個人的來訪問數(shù)據(jù)庫,從而避免對于數(shù)據(jù)庫訪問壓力過大,但這也會影響查詢的性能,因?yàn)榇藭r會讓查詢的性能從并行變成了串行,我們可以采用tryLock方法 + double check來解決這樣的問題。

假設(shè)現(xiàn)在線程1過來訪問,他查詢緩存沒有命中,但是此時他獲得到了鎖的資源,那么線程1就會一個人去執(zhí)行邏輯,假設(shè)現(xiàn)在線程2過來,線程2在執(zhí)行過程中,并沒有獲得到鎖,那么線程2就可以進(jìn)行到休眠,直到線程1把鎖釋放后,線程2獲得到鎖,然后再來執(zhí)行邏輯,此時就能夠從緩存中拿到數(shù)據(jù)了。

解決方案二、邏輯過期方案

方案分析:我們之所以會出現(xiàn)這個緩存擊穿問題,主要原因是在于我們對key設(shè)置了過期時間,假設(shè)我們不設(shè)置過期時間,其實(shí)就不會有緩存擊穿的問題,但是不設(shè)置過期時間,這樣數(shù)據(jù)不就一直占用我們內(nèi)存了嗎,我們可以采用邏輯過期方案。

我們把過期時間設(shè)置在 redis的value中,注意:這個過期時間并不會直接作用于redis,而是我們后續(xù)通過邏輯去處理。假設(shè)線程1去查詢緩存,然后從value中判斷出來當(dāng)前的數(shù)據(jù)已經(jīng)過期了,此時線程1去獲得互斥鎖,那么其他線程會進(jìn)行阻塞,獲得了鎖的線程他會開啟一個 線程去進(jìn)行 以前的重構(gòu)數(shù)據(jù)的邏輯,直到新開的線程完成這個邏輯后,才釋放鎖, 而線程1直接進(jìn)行返回,假設(shè)現(xiàn)在線程3過來訪問,由于線程線程2持有著鎖,所以線程3無法獲得鎖,線程3也直接返回?cái)?shù)據(jù),只有等到新開的線程2把重建數(shù)據(jù)構(gòu)建完后,其他線程才能走返回正確的數(shù)據(jù)。

這種方案巧妙在于,異步的構(gòu)建緩存,缺點(diǎn)在于在構(gòu)建完緩存之前,返回的都是臟數(shù)據(jù)。

進(jìn)行對比

互斥鎖方案:由于保證了互斥性,所以數(shù)據(jù)一致,且實(shí)現(xiàn)簡單,因?yàn)閮H僅只需要加一把鎖而已,也沒其他的事情需要操心,所以沒有額外的內(nèi)存消耗,缺點(diǎn)在于有鎖就有死鎖問題的發(fā)生,且只能串行執(zhí)行性能肯定受到影響

邏輯過期方案: 線程讀取過程中不需要等待,性能好,有一個額外的線程持有鎖去進(jìn)行重構(gòu)數(shù)據(jù),但是在重構(gòu)數(shù)據(jù)完成前,其他的線程只能返回之前的數(shù)據(jù),且實(shí)現(xiàn)起來麻煩

?利用互斥鎖解決緩存擊穿問題

核心思路:相較于原來從緩存中查詢不到數(shù)據(jù)后直接查詢數(shù)據(jù)庫而言,現(xiàn)在的方案是 進(jìn)行查詢之后,如果從緩存沒有查詢到數(shù)據(jù),則進(jìn)行互斥鎖的獲取,獲取互斥鎖后,判斷是否獲得到了鎖,如果沒有獲得到,則休眠,過一會再進(jìn)行嘗試,直到獲取到鎖為止,才能進(jìn)行查詢

如果獲取到了鎖的線程,再去進(jìn)行查詢,查詢后將數(shù)據(jù)寫入redis,再釋放鎖,返回?cái)?shù)據(jù),利用互斥鎖就能保證只有一個線程去執(zhí)行操作數(shù)據(jù)庫的邏輯,防止緩存擊穿

操作鎖的代碼:

核心思路就是利用redis的setnx方法來表示獲取鎖,該方法含義是redis中如果沒有這個key,則插入成功,返回1,在stringRedisTemplate中返回true, 如果有這個key則插入失敗,則返回0,在stringRedisTemplate返回false,我們可以通過true,或者是false,來表示是否有線程成功插入key,成功插入的key的線程我們認(rèn)為他就是獲得到鎖的線程。

private boolean tryLock(String key) {Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);
}private void unlock(String key) {stringRedisTemplate.delete(key);
}

操作代碼:

public Shop queryWithMutex(Long id)  {String key = CACHE_SHOP_KEY + id;// 1、從redis中查詢商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get("key");// 2、判斷是否存在if (StrUtil.isNotBlank(shopJson)) {// 存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判斷命中的值是否是空值if (shopJson != null) {//返回一個錯誤信息return null;}// 4.實(shí)現(xiàn)緩存重構(gòu)//4.1 獲取互斥鎖String lockKey = "lock:shop:" + id;Shop shop = null;try {boolean isLock = tryLock(lockKey);// 4.2 判斷否獲取成功if(!isLock){//4.3 失敗,則休眠重試Thread.sleep(50);return queryWithMutex(id);}//4.4 成功,根據(jù)id查詢數(shù)據(jù)庫shop = getById(id);// 5.不存在,返回錯誤if(shop == null){//將空值寫入redisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);//返回錯誤信息return null;}//6.寫入redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_NULL_TTL,TimeUnit.MINUTES);}catch (Exception e){throw new RuntimeException(e);}finally {//7.釋放互斥鎖unlock(lockKey);}return shop;}

利用邏輯過期解決緩存擊穿問題

需求:修改根據(jù)id查詢商鋪的業(yè)務(wù),基于邏輯過期方式來解決緩存擊穿問題

思路分析:當(dāng)用戶開始查詢redis時,判斷是否命中,如果沒有命中則直接返回空數(shù)據(jù),不查詢數(shù)據(jù)庫,而一旦命中后,將value取出,判斷value中的過期時間是否滿足,如果沒有過期,則直接返回redis中的數(shù)據(jù),如果過期,則在開啟獨(dú)立線程后直接返回之前的數(shù)據(jù),獨(dú)立線程去重構(gòu)數(shù)據(jù),重構(gòu)完成后釋放互斥鎖。

如果封裝數(shù)據(jù):因?yàn)楝F(xiàn)在redis中存儲的數(shù)據(jù)的value需要帶上過期時間,此時要么你去修改原來的實(shí)體類,要么你

步驟一、

新建一個實(shí)體類,我們采用第二個方案,這個方案,對原來代碼沒有侵入性。

@Data
public class RedisData {private LocalDateTime expireTime;private Object data;
}

步驟二、

ShopServiceImpl 新增此方法,利用單元測試進(jìn)行緩存預(yù)熱

    private void saveShop2Redis(Long id, Long expireSeconds) {//1.查詢店鋪信息Shop shop = getById(id);//2.封裝邏輯過期時間RedisData redisData = new RedisData();redisData.setData(shop);redisData.setExpireSeconds(LocalDateTime.now().plusSeconds(expireSeconds));//3.寫入RedisstringRedisTemplate.opsForValue().set("lock:" + id, JSONUtil.toJsonStr(redisData));}

?在測試類中

    @Testvoid test() {shopService.saveShop2Redis(1L,10L);}

步驟三:正式代碼

ShopServiceImpl

private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
public Shop queryWithLogicalExpire( Long id ) {String key = CACHE_SHOP_KEY + id;// 1.從redis查詢商鋪緩存String json = stringRedisTemplate.opsForValue().get(key);// 2.判斷是否存在if (StrUtil.isBlank(json)) {// 3.存在,直接返回return null;}// 4.命中,需要先把json反序列化為對象RedisData redisData = JSONUtil.toBean(json, RedisData.class);Shop shop = JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);LocalDateTime expireTime = redisData.getExpireTime();// 5.判斷是否過期if(expireTime.isAfter(LocalDateTime.now())) {// 5.1.未過期,直接返回店鋪信息return shop;}// 5.2.已過期,需要緩存重建// 6.緩存重建// 6.1.獲取互斥鎖String lockKey = LOCK_SHOP_KEY + id;boolean isLock = tryLock(lockKey);// 6.2.判斷是否獲取鎖成功if (isLock){CACHE_REBUILD_EXECUTOR.submit( ()->{try{//重建緩存this.saveShop2Redis(id,20L);}catch (Exception e){throw new RuntimeException(e);}finally {unlock(lockKey);}});}// 6.4.返回過期的商鋪信息return shop;
}

這期就到這里 , 下期再見 !

晚安 !

http://aloenet.com.cn/news/34262.html

相關(guān)文章:

  • 國家水資源監(jiān)控能力建設(shè)網(wǎng)站semir是什么牌子衣服
  • 黃岡黃頁寧波網(wǎng)絡(luò)推廣seo軟件
  • 珠海營銷營網(wǎng)站建設(shè)公司培訓(xùn)機(jī)構(gòu)不退費(fèi)最有效方式
  • 深圳網(wǎng)站建設(shè) 推薦xtdseo百度系app有哪些
  • 做網(wǎng)站算軟件開發(fā)么長尾關(guān)鍵詞在線查詢
  • 建設(shè)網(wǎng)站開通網(wǎng)線多少錢資源網(wǎng)站優(yōu)化排名優(yōu)化
  • 北京網(wǎng)站推廣|網(wǎng)站制作|網(wǎng)絡(luò)推廣|網(wǎng)站建設(shè)7個湖北seo網(wǎng)站推廣策略
  • 沈陽微信網(wǎng)站搜索引擎優(yōu)化的要點(diǎn)
  • 三亞網(wǎng)站建設(shè)哪家好760關(guān)鍵詞排名查詢
  • 做網(wǎng)站用win還是li注冊百度賬號
  • 湖南建設(shè)人力資源官方網(wǎng)站萬能軟文模板
  • 廣西做網(wǎng)站口碑營銷方案
  • wordpress去掉導(dǎo)航欄武漢seo關(guān)鍵字推廣
  • 中山專業(yè)制作網(wǎng)站武漢網(wǎng)絡(luò)推廣自然排名
  • 彭陽門戶網(wǎng)站建設(shè)網(wǎng)絡(luò)推廣的方式和途徑有哪些
  • 做網(wǎng)站搞個物理服務(wù)器引流推廣犯法嗎
  • 網(wǎng)站沒有問題但是一直做不上首頁seo托管
  • 網(wǎng)站程序設(shè)計(jì)百度鏈接收錄提交入口
  • 學(xué)做效果圖的網(wǎng)站有哪些新手電商運(yùn)營從哪開始學(xué)
  • 網(wǎng)站底部樣式智能建站平臺
  • 網(wǎng)站開發(fā)技術(shù)項(xiàng)目代碼搜索南寧seo外包要求
  • 做網(wǎng)站業(yè)務(wù)員怎么樣為企業(yè)策劃一次網(wǎng)絡(luò)營銷活動
  • 怎么做新網(wǎng)站的推廣下載優(yōu)化大師并安裝
  • 正規(guī)網(wǎng)站建設(shè)官網(wǎng)上海做網(wǎng)絡(luò)口碑優(yōu)化的公司
  • 電商網(wǎng)絡(luò)運(yùn)營浙江搜索引擎優(yōu)化
  • 鄭州企業(yè)網(wǎng)站優(yōu)化哪家便宜2022適合小學(xué)生的簡短新聞
  • 山西網(wǎng)站制作公司百度小說官網(wǎng)
  • 照片做視頻ppt模板下載網(wǎng)站好seo關(guān)鍵詞排名優(yōu)化價格
  • 做電影網(wǎng)站涉及的侵權(quán)問題網(wǎng)盤搜索神器
  • 做釣魚網(wǎng)站要什么工具中企動力做網(wǎng)站推廣靠譜嗎