最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文帶你搞懂Redis分布式鎖

 更新時間:2022年09月19日 08:28:41   作者:指北君  
本篇文章主要來介紹一下如何Redis實現(xiàn)分布式鎖的演進(jìn)過程,以及為什么不能直接用Setnx實現(xiàn)分布式鎖,文中的示例代碼講解詳細(xì),需要的可以參考一下

1、分布式鎖簡介

分布式鎖是控制分布式系統(tǒng)不同進(jìn)程共同訪問共享資源的一種鎖的實現(xiàn)。如果不同的系統(tǒng)或同一個系統(tǒng)的不同主機(jī)之間共享了某個臨界資源,往往需要互斥來防止彼此干擾,以保證一致性。

業(yè)界流行的分布式鎖實現(xiàn),一般有這3種方式:

  • 基于數(shù)據(jù)庫實現(xiàn)的分布式鎖
  • 基于Redis實現(xiàn)的分布式鎖
  • 基于Zookeeper實現(xiàn)的分布式鎖

這里主要介紹如何通過 Redis 來實現(xiàn)分布式鎖。在介紹 Redis 分布式鎖之前,我們首先介紹一下實現(xiàn)Redis 分布式鎖的關(guān)鍵命令。

2、setnx

setnx key value

Setnx(SET if Not eXists) 命令在指定的 key 不存在時,為 key 設(shè)置指定的值。

設(shè)置成功,返回 1 。設(shè)置失敗,返回 0 。

PS:Redis 官方是不推薦基于 setnx 命令來實現(xiàn)分布式鎖的,因為會存在很多問題,

①、單點問題。比如:

1、客戶端A 從master拿到鎖lock01

2、master正要把lock01同步(Redis的主從同步通常是異步的)給slave時,突然宕機(jī)了,導(dǎo)致lock01沒同步給slave

3、主從切換,slave節(jié)點被晉級為master節(jié)點

4、客戶端B到master拿lock01照樣能拿到。這樣必將導(dǎo)致同一把鎖被多人使用。

②、鎖的高級用法,比如讀寫鎖、可重入鎖等等,setnx 都比較難實現(xiàn)。

這里先介紹基于 sentnx 實現(xiàn)的分布式鎖,后面會介紹官方推薦的基于 redisson 來實現(xiàn)分布式鎖。

3、Redis-分布式鎖-階段1

接到上文,查詢?nèi)壏诸悢?shù)據(jù),如果我們部署了多個商品服務(wù),然后多個線程同時去獲取三級分類數(shù)據(jù),如果不加分布式鎖,就會導(dǎo)致,每一個部署的商品服務(wù)第一次查詢都會走 DB。

public?Map<String,?List<Catelog2Vo>>?getCatelogJsonWithRedisLock()?throws?InterruptedException?{
????//?一、獲取分布式鎖
????Boolean?lock?=?stringRedisTemplate.opsForValue().setIfAbsent("lock",?"111");

????if(lock){
????????//?true?表示加鎖成功,執(zhí)行相關(guān)業(yè)務(wù)
????????Map<String,?List<Catelog2Vo>>?dataFromDb?=?getDataFromDb();
????????stringRedisTemplate.delete("lock");
????????return?dataFromDb;
????}else{
????????System.out.println("獲取分布式鎖失敗...等待重試...");
????????//加鎖失敗...重試機(jī)制
????????//休眠一百毫秒
????????try?{
????????????TimeUnit.MILLISECONDS.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//自旋的方式
????????return?getCatelogJsonWithRedisLock();
????}
}

4、Redis-分布式鎖-階段2

設(shè)置鎖自動過期

public?Map<String,?List<Catelog2Vo>>?getCatelogJsonWithRedisLock()?throws?InterruptedException?{
????//?一、獲取分布式鎖
????Boolean?lock?=?stringRedisTemplate.opsForValue().setIfAbsent("lock",?"111");

????if(lock){
????????//?true?表示加鎖成功,執(zhí)行相關(guān)業(yè)務(wù)
????????//?設(shè)置過期時間
????????stringRedisTemplate.expire("lock",30,TimeUnit.SECONDS);
????????Map<String,?List<Catelog2Vo>>?dataFromDb?=?getDataFromDb();
????????stringRedisTemplate.delete("lock");
????????return?dataFromDb;
????}else{
????????System.out.println("獲取分布式鎖失敗...等待重試...");
????????//加鎖失敗...重試機(jī)制
????????//休眠一百毫秒
????????try?{
????????????TimeUnit.MILLISECONDS.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//自旋的方式
????????return?getCatelogJsonWithRedisLock();
????}
}

5、Redis-分布式鎖-階段3

setnx 命令和過期時間保證原子性。

public?Map<String,?List<Catelog2Vo>>?getCatelogJsonWithRedisLock()?throws?InterruptedException?{
????//?一、獲取分布式鎖
????Boolean?lock?=?stringRedisTemplate.opsForValue().setIfAbsent("lock",?"111",30,TimeUnit.SECONDS);

????if(lock){
????????//?true?表示加鎖成功,執(zhí)行相關(guān)業(yè)務(wù)
????????//?設(shè)置過期時間
????????//stringRedisTemplate.expire("lock",30,TimeUnit.SECONDS);
????????Map<String,?List<Catelog2Vo>>?dataFromDb?=?getDataFromDb();
????????stringRedisTemplate.delete("lock");
????????return?dataFromDb;
????}else{
????????System.out.println("獲取分布式鎖失敗...等待重試...");
????????//加鎖失敗...重試機(jī)制
????????//休眠一百毫秒
????????try?{
????????????TimeUnit.MILLISECONDS.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//自旋的方式
????????return?getCatelogJsonWithRedisLock();
????}
}

6、Redis-分布式鎖-階段4

保證刪除的是自己的鎖。

public?Map<String,?List<Catelog2Vo>>?getCatelogJsonWithRedisLock()?throws?InterruptedException?{
????//?一、獲取分布式鎖
????String?uuid?=?UUID.randomUUID().toString();
????Boolean?lock?=?stringRedisTemplate.opsForValue().setIfAbsent("lock",?uuid,30,TimeUnit.SECONDS);

????if(lock){
????????//?true?表示加鎖成功,執(zhí)行相關(guān)業(yè)務(wù)?
????????//?設(shè)置過期時間
????????//stringRedisTemplate.expire("lock",30,TimeUnit.SECONDS);
????????Map<String,?List<Catelog2Vo>>?dataFromDb?=?getDataFromDb();
????????String?lockValue?=?stringRedisTemplate.opsForValue().get("lock");
????????if(uuid.equals(lockValue)){
????????????stringRedisTemplate.delete("lock");
????????}
????????return?dataFromDb;
????}else{
????????System.out.println("獲取分布式鎖失敗...等待重試...");
????????//加鎖失敗...重試機(jī)制
????????//休眠一百毫秒
????????try?{
????????????TimeUnit.MILLISECONDS.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//自旋的方式
????????return?getCatelogJsonWithRedisLock();
????}
}

7、Redis-分布式鎖-階段5

通過Lua腳本保證刪除鎖和判斷鎖兩個操作原子性

public?Map<String,?List<Catelog2Vo>>?getCatelogJsonWithRedisLock(){
????//?一、獲取分布式鎖
????String?uuid?=?UUID.randomUUID().toString();
????Boolean?lock?=?stringRedisTemplate.opsForValue().setIfAbsent("lock",?uuid,30,TimeUnit.SECONDS);

????if?(lock)?{
????????System.out.println("獲取分布式鎖成功...");
????????Map<String,?List<Catelog2Vo>>?dataFromDb?=?null;
????????try?{
????????????//加鎖成功...執(zhí)行業(yè)務(wù)
????????????dataFromDb?=?getDataFromDb();
????????}?finally?{
????????????String?script?=?"if?redis.call('get',?KEYS[1])?==?ARGV[1]?then?return?redis.call('del',?KEYS[1])?else?return?0?end";

????????????//刪除鎖
????????????stringRedisTemplate.execute(new?DefaultRedisScript<Long>(script,?Long.class),?Arrays.asList("lock"),?uuid);

????????}
????????//先去redis查詢下保證當(dāng)前的鎖是自己的
????????//獲取值對比,對比成功刪除=原子性?lua腳本解鎖
????????//?String?lockValue?=?stringRedisTemplate.opsForValue().get("lock");
????????//?if?(uuid.equals(lockValue))?{
????????//?????//刪除我自己的鎖
????????//?????stringRedisTemplate.delete("lock");
????????//?}

????????return?dataFromDb;
????}else{
????????System.out.println("獲取分布式鎖失敗...等待重試...");
????????//加鎖失敗...重試機(jī)制
????????//休眠一百毫秒
????????try?{
????????????TimeUnit.MILLISECONDS.sleep(100);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????//自旋的方式
????????return?getCatelogJsonWithRedisLock();
????}
}

這也是分布式鎖的最終模式,需要保證兩個點:加鎖【設(shè)置鎖+過期時間】和刪除鎖【判斷+刪除】原子性。

到此這篇關(guān)于一文帶你搞懂Redis分布式鎖的文章就介紹到這了,更多相關(guān)Redis分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud+SpringBoot項目搭建結(jié)構(gòu)層次的實例

    SpringCloud+SpringBoot項目搭建結(jié)構(gòu)層次的實例

    這篇文章詳細(xì)介紹了SpringCloud項目的架構(gòu)層次及其搭建經(jīng)驗,包括Controller層、Service層、Repository層、Entity層、DTO層、Exception層等,通過文字和圖片的形式,幫助讀者理解如何組織和實現(xiàn)一個SpringBoot項目的不同層次
    2025-01-01
  • Java實戰(zhàn)之實現(xiàn)OA辦公管理系統(tǒng)

    Java實戰(zhàn)之實現(xiàn)OA辦公管理系統(tǒng)

    這篇文章主要介紹了如何通過Java實現(xiàn)OA辦公管理系統(tǒng),文章采用到了JSP、JQuery、Ajax等技術(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-02-02
  • 在spring?boot3中使用native?image的最新方法

    在spring?boot3中使用native?image的最新方法

    這篇文章主要介紹了在spring?boot3中使用native?image?,今天我們用具體的例子來給大家演示一下如何正確的將spring boot3的應(yīng)用編譯成為native image,需要的朋友可以參考下
    2023-01-01
  • WebSocket無法注入屬性的問題及解決方案

    WebSocket無法注入屬性的問題及解決方案

    這篇文章主要介紹了WebSocket無法注入屬性的問題及解決方法,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • SpringData JPA中@OneToMany和@ManyToOne的用法詳解

    SpringData JPA中@OneToMany和@ManyToOne的用法詳解

    這篇文章主要介紹了SpringData JPA中@OneToMany和@ManyToOne的用法詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • IntelliJ IDEA 2020.2 配置大全詳細(xì)圖文教程(更新中)

    IntelliJ IDEA 2020.2 配置大全詳細(xì)圖文教程(更新中)

    這篇文章主要介紹了IntelliJ IDEA 2020.2 配置大全(更新中),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • SpringMVC執(zhí)行過程詳細(xì)講解

    SpringMVC執(zhí)行過程詳細(xì)講解

    MVC是一種軟件設(shè)計典范,用一種業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示分離的方法組織代碼,將業(yè)務(wù)邏輯聚集到一個組件里面,在改進(jìn)和個性化定制界面及用戶交互的同時,不需要重新編寫業(yè)務(wù)邏輯,MVC分層有助于管理和架構(gòu)復(fù)雜的應(yīng)用程序
    2022-08-08
  • Spring Boot 項目啟動自動執(zhí)行方法的兩種實現(xiàn)方式

    Spring Boot 項目啟動自動執(zhí)行方法的兩種實現(xiàn)方式

    這篇文章主要介紹了Spring Boot 項目啟動自動執(zhí)行方法的兩種實現(xiàn)方式,幫助大家更好的理解和學(xué)習(xí)使用Spring Boot框架,感興趣的朋友可以了解下
    2021-05-05
  • MyBatis游標(biāo)Cursor的正確使用和百萬數(shù)據(jù)傳輸?shù)膬?nèi)存測試

    MyBatis游標(biāo)Cursor的正確使用和百萬數(shù)據(jù)傳輸?shù)膬?nèi)存測試

    這篇文章主要介紹了MyBatis游標(biāo)Cursor的正確使用和百萬數(shù)據(jù)傳輸?shù)膬?nèi)存測試,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Spring?boot?集成?MQTT詳情

    Spring?boot?集成?MQTT詳情

    這篇文章主要介紹了Spring?boot?集成?MQTT詳情,MQTT是一種基于發(fā)布/訂閱模式的"輕量級"通訊協(xié)議,可以以極少的代碼和有限的帶寬為連接遠(yuǎn)程設(shè)備提供實時可靠的消息服,下文更多相關(guān)介紹,需要的小伙伴可以參考一下
    2022-04-04

最新評論

茂名市| 吴川市| 博乐市| 邢台市| 博客| 正安县| 元氏县| 德阳市| 咸宁市| 闸北区| 陇西县| 鄄城县| 仁布县| 柘城县| 那坡县| 三穗县| 利津县| 卓尼县| 航空| 永川市| 电白县| 图木舒克市| 温宿县| 桦甸市| 高雄市| 宁城县| 当阳市| 湘乡市| 沛县| 达拉特旗| 青神县| 上杭县| 景谷| 新兴县| 延吉市| 达拉特旗| 睢宁县| 洛扎县| 横峰县| 萨迦县| 满洲里市|