springboot redisson 分布式鎖入門與實戰

Spring Boot3 Redisson 項目地址

https://gitee.com/supervol/loong-springboot-study

(記得給個start,感謝)

Redisson?介紹

????????在分布式系統中,多節點部署的應用對共享資源(如數據庫記錄、緩存鍵、文件)的并發訪問需要分布式鎖來保證互斥性,避免數據不一致問題。Spring Boot 3 生態中,Redisson?是實現分布式鎖的主流方案之一 —— 它基于 Redis 封裝了完整的分布式鎖功能,解決了原生 Redis 實現鎖的諸多痛點(如手動續期、不可重入、釋放他人鎖等),提供了高可用、易擴展的分布式鎖能力。

Redisson 核心

1. 為什么需要分布式鎖

????????單機應用中,synchronized?或?java.util.concurrent.locks.Lock?可解決并發問題,但分布式系統中多節點共享資源時,單機鎖失效(各節點內存獨立),需跨節點的 “全局鎖”:

  • 核心需求:互斥性(同一時間僅一個節點持有鎖)、安全性(避免死鎖)、可用性(鎖服務不宕機)、重入性(同一線程可重復獲取鎖)、公平性(可選,按請求順序獲取)。
  • 原生 Redis 痛點:需手動實現?setNx+expire?原子操作、手動處理鎖續期、無法原生支持重入、可能釋放他人鎖,而 Redisson 封裝了這些細節。

2. Redisson 是什么

????????Redisson 是基于 Redis 的?Java 分布式客戶端,不僅提供 Redis 基礎操作(如字符串、哈希、列表),還內置了大量分布式場景工具類,核心能力包括:

  • 分布式鎖(可重入鎖、公平鎖、讀寫鎖等);
  • 分布式集合(分布式 Map、Set、Queue);
  • 分布式信號量、計數器、限流器;
  • 支持 Redis 單機、集群、哨兵、主從等所有部署模式。

????????其中,分布式鎖是 Redisson 最核心的功能,它通過 Redis 的?Hash?數據結構和 Lua 腳本保證鎖的原子性,同時提供 “看門狗(Watch Dog)” 機制解決鎖續期問題。

Redisson 使用

????????Redisson 提供多種分布式鎖類型,可重入鎖(RLock)?是最常用的基礎鎖,其他鎖(公平鎖、讀寫鎖等)均基于其擴展。

1. 可重入鎖(RLock)

????????可重入鎖支持同一線程多次獲取鎖(解決 “自己鎖自己” 的問題),且內置?Watch Dog 自動續期?機制,避免業務未執行完鎖已過期。

(1)核心 API

方法功能說明
lock()阻塞獲取鎖,默認啟用 Watch Dog(leaseTime=-1),直到獲取成功
lock(long leaseTime, TimeUnit unit)帶過期時間的鎖,leaseTime?后自動釋放,禁用 Watch Dog
tryLock()非阻塞獲取鎖,立即返回?true(成功)或?false(失敗)
tryLock(long waitTime, long leaseTime, TimeUnit unit)帶等待時間的非阻塞鎖:
-?waitTime:獲取鎖的最大等待時間(超時返回?false
-?leaseTime:鎖的過期時間(0 或 -1 啟用 Watch Dog)
unlock()釋放鎖,必須在?finally?中調用,避免死鎖
isHeldByCurrentThread()判斷當前線程是否持有鎖,避免釋放他人鎖

(2)代碼示例

????????生產環境中優先使用?tryLock?避免無限阻塞,同時在?finally?中安全釋放鎖:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class OrderService {@Autowiredprivate RedissonClient redissonClient;// 分布式鎖的 Key(需保證業務唯一性,如“訂單創建_用戶ID”)private static final String LOCK_KEY = "order:create:%s";/*** 創建訂單(分布式鎖保護)* @param userId 用戶ID(用于生成唯一鎖Key)*/public void createOrder(Long userId) {RLock lock = null;try {// 1. 生成唯一鎖Key(按用戶ID區分,避免鎖沖突)String lockKey = String.format(LOCK_KEY, userId);// 2. 獲取可重入鎖lock = redissonClient.getLock(lockKey);// 3. 嘗試獲取鎖:等待3秒,持有5秒(若5秒內未釋放,鎖自動過期)boolean isLocked = lock.tryLock(3, 5, TimeUnit.SECONDS);if (!isLocked) {// 4. 獲取鎖失敗,返回友好提示throw new RuntimeException("當前操作過頻繁,請稍后再試");}// 5. 獲取鎖成功,執行核心業務(如創建訂單、扣減庫存)System.out.println("獲取鎖成功,執行訂單創建邏輯...");// 模擬業務耗時(如2秒)TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException("訂單創建失敗");} finally {// 6. 安全釋放鎖:僅釋放當前線程持有的鎖if (lock != null && lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("鎖釋放成功");}}}
}

2. Watch Dog 自動續期

????????當?leaseTime?未設置(或設為 -1)時,Redisson 會啟動?Watch Dog 機制,解決 “業務未執行完鎖已過期” 的問題:

  • 原理:Watch Dog 是一個后臺線程,在鎖快過期時(默認剩余 10 秒)自動將鎖的過期時間延長至 30 秒;
  • 默認配置:鎖默認過期時間 30 秒,續期間隔 10 秒;
  • 禁用場景:若手動設置?leaseTime(如 5 秒),Watch Dog 會失效,鎖會在?leaseTime?后強制釋放,需確保?leaseTime?大于業務執行時間。

3. 其他常用鎖類型

????????Redisson 提供多種鎖類型,滿足不同分布式場景需求:

(1)公平鎖(RedissonFairLock)

????????按請求順序獲取鎖,避免 “饑餓問題”(某些線程長期獲取不到鎖),適用于對公平性要求高的場景(如秒殺排隊)。使用示例

// 獲取公平鎖(替換 getLock 為 getFairLock)
RLock fairLock = redissonClient.getFairLock("order:create:1001");
try {if (fairLock.tryLock(3, 5, TimeUnit.SECONDS)) {// 執行公平鎖保護的業務邏輯}
} finally {if (fairLock != null && fairLock.isHeldByCurrentThread()) {fairLock.unlock();}
}

(2)讀寫鎖(RReadWriteLock)

????????讀鎖共享,寫鎖互斥,適用于 “讀多寫少” 的場景(如商品詳情查詢、庫存更新),提高并發效率:

  • 讀鎖(共享):多個線程可同時獲取讀鎖,互不阻塞;
  • 寫鎖(互斥):僅一個線程可獲取寫鎖,且寫鎖與讀鎖互斥。

使用示例

// 獲取讀寫鎖
RReadWriteLock rwLock = redissonClient.getReadWriteLock("product:info:1001");// 1. 讀操作(獲取讀鎖)
RLock readLock = rwLock.readLock();
try {readLock.lock(5, TimeUnit.SECONDS);System.out.println("獲取讀鎖,查詢商品詳情..."); // 多個線程可同時執行
} finally {readLock.unlock();
}// 2. 寫操作(獲取寫鎖)
RLock writeLock = rwLock.writeLock();
try {writeLock.lock(5, TimeUnit.SECONDS);System.out.println("獲取寫鎖,更新商品庫存..."); // 僅一個線程執行
} finally {writeLock.unlock();
}

(3)聯鎖(RMultiLock)

????????需同時獲取多個鎖,全部獲取成功才繼續執行,適用于 “多資源協同鎖定” 場景(如轉賬需同時鎖定付款方和收款方賬戶)。使用示例

// 1. 獲取兩個獨立的鎖
RLock lock1 = redissonClient.getLock("account:lock:1001"); // 付款方賬戶鎖
RLock lock2 = redissonClient.getLock("account:lock:1002"); // 收款方賬戶鎖// 2. 創建聯鎖(需全部鎖獲取成功才生效)
RMultiLock multiLock = new RedissonMultiLock(lock1, lock2);try {// 3. 嘗試獲取聯鎖(等待3秒,持有5秒)if (multiLock.tryLock(3, 5, TimeUnit.SECONDS)) {System.out.println("獲取所有鎖成功,執行轉賬邏輯...");}
} finally {if (multiLock != null && multiLock.isHeldByCurrentThread()) {multiLock.unlock();}
}

(4)紅鎖(RRedLock)

????????在多個獨立 Redis 節點(非集群,避免集群腦裂)上獲取鎖,超過半數節點獲取成功即視為鎖獲取成功,適用于對鎖可用性要求極高的場景(如金融交易),避免單點 Redis 故障導致鎖失效。使用示例

// 1. 在3個獨立Redis節點上創建鎖
RLock lock1 = redissonClient.getLock("order:pay:1001"); // 節點1
RLock lock2 = redissonClient.getLock("order:pay:1001"); // 節點2(需單獨配置RedissonClient)
RLock lock3 = redissonClient.getLock("order:pay:1001"); // 節點3// 2. 創建紅鎖(超過半數節點成功即生效)
RRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {if (redLock.tryLock(3, 5, TimeUnit.SECONDS)) {System.out.println("紅鎖獲取成功,執行支付邏輯...");}
} finally {if (redLock != null && redLock.isHeldByCurrentThread()) {redLock.unlock();}
}

Redisson 示例

????????請參考項目地址中 springboot-lock/springboot-distributed-lock 模塊代碼。

Redisson 注意

1. 鎖 Key 設計:保證唯一性

????????鎖 Key 需與業務場景強綁定,避免不同業務共用一個 Key 導致鎖沖突。例如:

  • 訂單創建:order:create:{userId}(按用戶區分,避免同一用戶并發創建訂單);
  • 庫存扣減:stock:deduct:{productId}(按商品區分,避免不同商品庫存鎖沖突)。

2. 安全釋放鎖:避免釋放他人鎖

  • 必須在?finally?中釋放鎖,確保業務異常時鎖仍能釋放;
  • 釋放前通過?isHeldByCurrentThread()?判斷當前線程是否持有鎖,避免釋放其他線程的鎖(如線程 A 超時未釋放,鎖被自動過期,線程 B 獲取鎖后,線程 A 恢復執行釋放了線程 B 的鎖)。

3. 鎖粒度:盡量減小鎖范圍

????????避免將整個業務流程加鎖,僅對 “共享資源修改” 的核心邏輯加鎖,減少鎖持有時間,提高并發效率。

4. Redis 高可用:避免鎖服務單點故障

????????分布式鎖依賴 Redis,需確保 Redis 高可用:

  • 開發環境:單機 Redis(帶持久化,避免重啟丟失鎖);
  • 生產環境:Redis 集群(3 主 3 從)或哨兵模式,避免單點 Redis 宕機導致鎖不可用。

5. 序列化配置:避免特殊字符問題

????????Redisson 默認使用?JDK 序列化,可能導致 Redis 中存儲的 Key/Value 包含特殊字符(如?\xAC\xED),建議改為?Jackson 序列化,提高可讀性。

Redisson 對比

特性原生 Redis 鎖(setNx+expire)Redisson 分布式鎖
重入性不支持(需手動維護線程標識和重入次數)原生支持(RLock)
自動續期不支持(需手動定時任務續期)支持(Watch Dog 機制)
鎖釋放安全可能釋放他人鎖(需手動判斷線程標識)自動判斷當前線程,安全釋放
鎖類型僅基礎互斥鎖支持公平鎖、讀寫鎖、聯鎖、紅鎖等
易用性需手動封裝(原子操作、異常處理)開箱即用,API 簡潔

????????顯然,Redisson 解決了原生 Redis 鎖的所有痛點,是 Spring Boot 3 分布式系統中實現分布式鎖的最優選擇

總結

????????在生產環境中,只需關注 “鎖 Key 設計”“鎖粒度控制”“Redis 高可用” 三個核心點,即可安全、高效地使用 Redisson 分布式鎖解決并發問題。Redisson 為 Spring Boot 3 提供了 “開箱即用” 的分布式鎖解決方案,核心優勢包括:

  1. 支持多種鎖類型(可重入鎖、公平鎖、讀寫鎖等),滿足不同業務場景;
  2. 內置 Watch Dog 自動續期,避免業務未完成鎖過期;
  3. 封裝原子操作和異常處理,簡化開發;
  4. 支持 Redis 所有部署模式,保證高可用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98778.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98778.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98778.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用 Tkinter + Requests 實現地理信息安全系統學習時長助手

?重磅!盹貓的個人小站正式上線啦~誠邀各位技術大佬前來探秘!? 這里有: 硬核技術干貨:編程技巧、開發經驗、踩坑指南,帶你解鎖技術新姿勢!趣味開發日常:代碼背后的腦洞故事、工具…

構建一個優雅的待辦事項應用:現代JavaScript實踐

構建一個優雅的待辦事項應用:現代JavaScript實踐本文將介紹如何使用現代JavaScript(ES6)和DOM操作創建一個功能完整的待辦事項應用,無需任何外部庫或框架。功能概述添加新任務標記任務為完成/未完成編輯任務內容刪除任務過濾任務&…

【數據可視化-111】93大閱兵后的軍費開支情況———2024年全球軍費開支分析:用Python和Pyecharts打造炫酷可視化大屏

🧑 博主簡介:曾任某智慧城市類企業算法總監,目前在美國市場的物流公司從事高級算法工程師一職,深耕人工智能領域,精通python數據挖掘、可視化、機器學習等,發表過AI相關的專利并多次在AI類比賽中獲獎。CSDN…

3.2.Maven-概述-介紹安裝

一.介紹:二.安裝:Maven的安裝比較簡單,因為他是綠色版的軟件,官方給我們提供Maven的安裝包就是一個zip壓縮包,在進行Maven安裝以及配置的時候,主要進行如下4步操作:第一步:把官方提供…

Kafka面試精講 Day 14:集群擴容與數據遷移

【Kafka面試精講 Day 14】集群擴容與數據遷移 在“Kafka面試精講”系列的第14天,我們將深入探討 Kafka 運維中最關鍵的操作之一:集群擴容與數據遷移。隨著業務增長,原始 Kafka 集群可能面臨磁盤不足、吞吐瓶頸或節點負載不均等問題&#xff…

字節一面 面經(補充版)

什么是RabbitMQ,特點是什么怎么理解保障消息的一致性String、StringBuffer、StringBuilder解釋一下線程安全先操作數據庫再刪緩存還是先刪緩存再操作數據庫這種辦法能杜絕數據不一致問題嗎解釋一下AOP介紹Redis的特點(Redis比較快)Redis為什么…

【MFC】對話框屬性:Absolute Align(絕對對齊)

前言 本文介紹對話框屬性中的Absolute Align(絕對對齊),同時給出相關示例便于理解。 目錄1 位置2 詳解3 示例1 位置 首先介紹一下這個屬性在哪里。 在資源視圖中雙擊對話框節點,打開該對話框; 鼠標右鍵工作區空白處,單擊屬性&…

【從0開始學習Java | 第17篇】集合(中-Set部分)

文章目錄Java集合之Set:無序不重復的元素容器一、Set接口的核心特性二、常用實現類及底層原理1. HashSet:基于哈希表的高效實現2. LinkedHashSet:保留插入順序的哈希實現3. TreeSet:基于紅黑樹的排序實現三、實現類對比與選擇建議…

玩轉Docker | 使用Docker部署dufs文件管理工具

玩轉Docker | 使用Docker部署dufs文件管理工具 前言 一、 dufs介紹 Dufs簡介 核心特性 ?? 靜態文件服務 ?? 文件夾打包下載 ?? 拖拽上傳文件/文件夾 ?? 文件在線創建、編輯與搜索 ? 斷點續傳與部分傳輸 ?? 細粒度訪問控制 ?? HTTPS 安全傳輸 ?? WebDAV 兼容支持…

【混合開發】vue+Android、iPhone、鴻蒙、win、macOS、Linux之android 把assert里的dist.zip 包解壓到sd卡里

一圖勝千言 上一篇有 <!-- 讀寫外部存儲 --> <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion"28"/> <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE&qu…

線程的創建.銷毀

線程線程的創建在 C 中&#xff0c;線程的創建核心是通過std::thread類實現的&#xff0c;其構造函數需要傳入一個可調用對象&#xff08;Callable Object&#xff09;作為線程入口。可調用對象包括普通函數、lambda 表達式、函數對象&#xff08;functor&#xff09;、類的成員…

MySQL基礎全面解析

MySQL作為最流行的關系型數據庫管理系統之一&#xff0c;是每一位開發者必備的核心技能。本文將系統性地解析MySQL的基礎知識&#xff0c;結合關鍵概念與實戰應用&#xff0c;幫助您構建扎實的數據庫基礎。1. SQL與NoSQL的本質區別SQL&#xff08;結構化查詢語言&#xff09;數…

4、幽絡源微服務項目實戰:后端公共模塊創建與引入多租戶模塊

前言 上節我們將電網巡檢系統的前端vue2項目創建、配置&#xff0c;并構建了最基礎的多租戶界面&#xff0c;本節來繼續構建后端的公共模塊、多租戶模塊&#xff0c;并將公共模塊引入到多租戶模塊中。 創建公共模塊和多租戶模塊 在back父工程下創建兩個Module&#xff0c;和…

STM32學習路線開啟篇:芯片簡介與課程簡介

編寫不易,請多多指教,覺得不錯可以關注一下,相互學習 前言 一、課程配套資源 1、面包板 2、面包板專用的跳線 3、面包板的飛線 4、杜邦線 5、STM32F103C8T6最小系統板 6、0.96寸的OLED顯示屏模塊 7、電位器 8、按鈕 9、LED燈 10、STLINK 11、USB轉串口(TTL)模塊 12、源蜂鳴器模…

圖像直方圖

圖像直方圖就是用來統計圖像像素值分布的。灰度圖分布讀取灰度圖phone cv2.imread(phone.png, cv2.IMREAD_GRAYSCALE) a phone.ravel() plt.hist(a, bins256) plt.show()如何可以獲得當前像素值分布讀取各通道的像素值分布img cv2.imread(phone.png) colors (b, g, r) for …

分類別柱狀圖(Vue3)

效果圖&#xff1a;需求&#xff1a;男女年齡段占比<template><div class"go-ClassifyBar01"><v-chartref"vChartRef":option"option"style"width: 100%; height: 800px"></v-chart></div> </templa…

Apache Dubbo學習筆記-使用Dubbo發布、調用服務

Apache Dubbo經常作為一個RPC框架來使用&#xff0c;這篇文章主要介紹使用Dubbo配合注冊中心來發布和調用服務。 Apache Dubbo和Spring Boot、JDK的版本對應關系。 Dubbo 分支最新版本JDKSpring Boot組件版本詳細說明3.3.x (當前文檔)3.3.08, 17, 212.x、3.x詳情- 版本變更記錄…

Python學習——字典和文件

前面python的學習中我們已經學習了python的函數和列表元組相關的內容&#xff0c;接下來我們來學習剩下的python語法&#xff1a;字典和文件 相關代碼已經上傳到作者的個人gitee&#xff1a;樓田莉子/Python 學習喜歡請點個贊謝謝 目錄 字典 創建字典 查找key 新增/修改元素 …

swiper插件的使用

官方網址&#xff1a;https://www.swiper.com.cn/ 1、點擊導航欄&#xff0c;獲取Swiper里邊的下載Swiper 2、選擇要下載的版本【本次案例版本5.4.5】&#xff0c;然后解壓縮文件夾&#xff0c;拿到swiper.min.js和swiper.min.css文件&#xff0c;放到項目對應的css文件和js文…

Vue3+JS 組合式 API 實戰:從項目痛點到通用 Hook 封裝

Vue3 組合式 API 的實戰技巧 —— 組合式 API 幫我解決了不少 Options API 難以應對的問題&#xff0c;尤其是在代碼復用和復雜組件維護上。一、為什么放棄 Options API&#xff1f;聊聊三年項目里的真實痛點?剛接觸 Vue3 時&#xff0c;我曾因 “慣性” 繼續用 Options API 寫…