在SpringBoot中如何利用Redis實(shí)現(xiàn)互斥鎖
在SpringBoot中利用Redis實(shí)現(xiàn)互斥鎖
基本知識
前提條件,有一個(gè)能夠在Springboot中使用Redis的項(xiàng)目,或者能夠直接開也行
為什么要實(shí)現(xiàn)互斥鎖:當(dāng)我們利用Redis存儲熱點(diǎn)數(shù)據(jù)時(shí),突然就過期失效或者被刪除了,導(dǎo)致大量請求同時(shí)訪問數(shù)據(jù)庫,增加了數(shù)據(jù)庫的負(fù)載。為減輕數(shù)據(jù)庫的負(fù)載我們利用互斥鎖。
業(yè)務(wù)的一個(gè)邏輯圖流程:
核心思路:相較于原來從緩存中查詢不到數(shù)據(jù)后直接查詢數(shù)據(jù)庫而言,現(xiàn)在的方案是 進(jìn)行查詢之后,如果從緩存沒有查詢到數(shù)據(jù),則進(jìn)行互斥鎖的獲取,獲取互斥鎖后,判斷是否獲得到了鎖,如果沒有獲得到,則休眠,過一會再進(jìn)行嘗試,直到獲取到鎖為止(這個(gè)嘗試,要重新從Redis再次嘗試獲取數(shù)據(jù),可能別的鎖已經(jīng)獲取到了),才能進(jìn)行查詢
如果獲取到了鎖的線程,再去進(jìn)行查詢,查詢后將數(shù)據(jù)寫入redis,再釋放鎖,返回?cái)?shù)據(jù),利用互斥鎖就能保證只有一個(gè)線程去執(zhí)行操作數(shù)據(jù)庫的邏輯,防止緩存擊穿
操作鎖的核心思路就是利用redis的setnx方法來表示獲取鎖,該方法含義是redis中如果沒有這個(gè)key,則插入成功,返回1
具體實(shí)現(xiàn)
設(shè)置鎖,刪除鎖
/** * 根據(jù)name對特定的數(shù)據(jù)進(jìn)行鎖 * @param name * @return */ public boolean setLock(String name) { return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(name, true, 10, TimeUnit.SECONDS)); } public boolean releaseLock(String name) { return Boolean.TRUE.equals(redisTemplate.delete(name)); }
具體流程實(shí)現(xiàn)
@GetMapping("/getOneByLock/{sequence}") public BaseResponse<Sentences> getOneByLock(@PathVariable long sequence) { // 從redis中查信息 String name = "test:redis:sentences:"+ sequence; Sentences sentence = (Sentences) redisTemplate.opsForValue().get(name); // 命中返回?cái)?shù)據(jù) if(sentence != null ){ redisTemplate.expire(name,2,TimeUnit.MINUTES); return ResultUtils.success(sentence); } // 未命中獲取鎖 String LOCK_NAME = "test:redis:lock:" + sequence; boolean lock = redisTemplate.opsForValue().get(LOCK_NAME) != null && (boolean) redisTemplate.opsForValue().get(LOCK_NAME); //如果lock等于false 那么就可以獲取到鎖并且,鎖住不許其他人操作 if(!lock){ return ResultUtils.success(setLockReleaseLockAboutSentence(LOCK_NAME,name,sequence)); } // 沒有獲取到鎖 休眠一段時(shí)間,并且反復(fù)檢測redis中的數(shù)據(jù)是否存在,或者鎖是否釋放 while(true){ try { Thread.sleep(1000); log.error("等待中"); } catch (InterruptedException e) { throw new RuntimeException(e); } // 檢查是否存在值 sentence = (Sentences) redisTemplate.opsForValue().get(name); if(sentence != null){ return ResultUtils.success(sentence); } boolean checkAgain = (boolean) redisTemplate.opsForValue().get(LOCK_NAME); if(!checkAgain){ sentence = setLockReleaseLockAboutSentence(LOCK_NAME,name,sequence); } return ResultUtils.success(sentence); } } public Sentences setLockReleaseLockAboutSentence(String LOCK_NAME,String redisName, long sequence){ // 設(shè)置 鎖值 為true setLock(LOCK_NAME); // 并且從數(shù)據(jù)中查取數(shù)據(jù) Sentences sentence = sentencesService.getById(sequence); // 這里為了明顯不能搶鎖設(shè)置一個(gè)睡眠時(shí)間 try { log.error("休眠中"); Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException(e); } // 把數(shù)據(jù)寫入Redis redisTemplate.opsForValue().set(redisName,sentence,2, TimeUnit.MINUTES); // 釋放鎖 releaseLock(LOCK_NAME); // 返回?cái)?shù)據(jù) return sentence; }
代碼說明,在這個(gè)代碼中為了演示明顯,獲取鎖中延遲3s,競爭鎖會延遲1s,下面的演示,初始時(shí)Redis中沒有數(shù)據(jù),只能去數(shù)據(jù)庫中取數(shù)據(jù),但是設(shè)置了互斥鎖,所以只能夠一個(gè)線程進(jìn)入數(shù)據(jù)庫取數(shù)據(jù),其他只能等待數(shù)據(jù)得到結(jié)果。
結(jié)果示意 redis中無數(shù)據(jù)
結(jié)果
最終效果是好的。redis中已存入數(shù)據(jù)
到此這篇關(guān)于在SpringBoot中利用Redis實(shí)現(xiàn)互斥鎖的文章就介紹到這了,更多相關(guān)SpringBoot互斥鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用SpringSecurity 進(jìn)行自定義Token校驗(yàn)
這篇文章主要介紹了使用SpringSecurity 進(jìn)行自定義Token校驗(yàn)操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06SpringBoot?將配置文件掛到?jar?包外面的操作方法
在 SpringBoot 中,可以將配置文件放在 jar 包外面,這樣可以方便地修改配置而不需要重新打包和部署,這篇文章主要介紹了SpringBoot?如何將配置文件掛到?jar?包外面,需要的朋友可以參考下2023-03-03java Class文件內(nèi)部結(jié)構(gòu)解析過程詳解
java class的文件結(jié)構(gòu),java class文件結(jié)構(gòu)是基于字節(jié)流的,用unicode進(jìn)行編碼,下面說說java Class文件內(nèi)部結(jié)構(gòu)分析2013-11-11使用Java第三方實(shí)現(xiàn)發(fā)送短信功能
這篇文章主要介紹了使用Java第三方實(shí)現(xiàn)發(fā)送短信功能,在一些開發(fā)中,經(jīng)常需要有給用戶發(fā)送短信接收驗(yàn)證碼的功能,那么在Java中該如何實(shí)現(xiàn)呢,今天我們就一起來看一看2023-03-03Java數(shù)據(jù)結(jié)構(gòu)之復(fù)雜度篇
算法復(fù)雜度分為時(shí)間復(fù)雜度和空間復(fù)雜度。其作用:?時(shí)間復(fù)雜度是度量算法執(zhí)行的時(shí)間長短;而空間復(fù)雜度是度量算法所需存儲空間的大小2022-01-01Mybatis-flex整合達(dá)夢數(shù)據(jù)庫的實(shí)現(xiàn)示例
本文討論了國產(chǎn)達(dá)夢數(shù)據(jù)庫與Mybatis-flex框架的整合過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10Spring cloud 查詢返回廣告創(chuàng)意實(shí)例代碼
在本篇文章里小編給大家整理的是關(guān)于Spring cloud 查詢返回廣告創(chuàng)意實(shí)例代碼,需要的朋友們可以跟著學(xué)習(xí)下。2019-08-08