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 提供了 “開箱即用” 的分布式鎖解決方案,核心優勢包括:
- 支持多種鎖類型(可重入鎖、公平鎖、讀寫鎖等),滿足不同業務場景;
- 內置 Watch Dog 自動續期,避免業務未完成鎖過期;
- 封裝原子操作和異常處理,簡化開發;
- 支持 Redis 所有部署模式,保證高可用。