分布式鎖實現方式:基于Redis的分布式鎖實現(Spring Boot + Redis)

Redis實現分布式鎖的原理

Redis分布式鎖基于其單線程執行命令的特性,通過原子操作實現多節點間的互斥訪問。下面從原理、實現、問題及優化四個方面詳細解析:

1.原子性與互斥性

Redis分布式鎖的核心是原子性操作

  1. 獲取鎖:使用SET key value NX EX timeout命令

    • NX(Not eXists):僅當key不存在時設置成功
    • EX timeout:設置過期時間,防止死鎖
    • 原子性:Redis單線程執行命令,確保多客戶端并發請求時只有一個能成功
  2. 釋放鎖:先驗證鎖持有者再刪除

    • 必須使用Lua腳本保證原子性,避免誤刪其他線程的鎖
-- 釋放鎖的Lua腳本
if redis.call('get', KEYS[1]) == ARGV[1] thenreturn redis.call('del', KEYS[1])
elsereturn 0
end
2.分布式鎖的實現步驟

1. 獲取鎖流程

  • 客戶端生成唯一標識(如UUID)作為鎖的值
  • 執行SET lock_key unique_id NX EX 10(10秒過期)
  • 返回OK表示獲取鎖成功,否則失敗

2. 釋放鎖流程

  • 客戶端攜帶鎖的唯一標識調用Lua腳本
  • 腳本先檢查鎖的值是否與傳入標識一致
  • 一致則刪除鎖,返回1;不一致返回0

示例

1. 添加依賴

pom.xml中添加Spring Data Redis依賴:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 配置Redis連接

application.yml中配置Redis服務器信息:

spring:redis:host: localhostport: 6379password: yourpassword  # 如果有密碼timeout: 5000mslettuce:pool:max-active: 8max-wait: -1msmax-idle: 8min-idle: 0
3. 創建分布式鎖接口

定義鎖的基本操作:

public interface RedisLock {/*** 嘗試獲取鎖* @param lockKey 鎖的鍵* @param requestId 請求標識(用于釋放鎖時校驗)* @param expireTime 鎖的過期時間* @param timeUnit 時間單位* @return 是否成功獲取鎖*/boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit timeUnit);/*** 釋放鎖* @param lockKey 鎖的鍵* @param requestId 請求標識* @return 是否成功釋放鎖*/boolean releaseLock(String lockKey, String requestId);
}
4. 實現分布式鎖(重點)

使用RedisTemplate實現鎖操作,關鍵在于:

  • 獲取鎖:使用setIfAbsent原子操作
  • 釋放鎖:使用Lua腳本保證原子性
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;import java.util.Collections;
import java.util.concurrent.TimeUnit;@Component
public class RedisLockImpl implements RedisLock {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 釋放鎖的Lua腳本:先驗證鎖的持有者,再刪除鎖private static final DefaultRedisScript<Long> RELEASE_LOCK_SCRIPT;static {RELEASE_LOCK_SCRIPT = new DefaultRedisScript<>();RELEASE_LOCK_SCRIPT.setScriptText("if redis.call('get', KEYS[1]) == ARGV[1] then " +"    return redis.call('del', KEYS[1]) " +"else " +"    return 0 " +"end");RELEASE_LOCK_SCRIPT.setResultType(Long.class);}@Overridepublic boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit timeUnit) {// 核心方法:原子性地設置鎖和過期時間Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, timeUnit);return result != null && result;}@Overridepublic boolean releaseLock(String lockKey, String requestId) {// 使用Lua腳本保證原子性Long result = redisTemplate.execute(RELEASE_LOCK_SCRIPT,Collections.singletonList(lockKey),requestId);return result != null && result == 1L;}
}
5. 使用分布式鎖
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.UUID;
import java.util.concurrent.TimeUnit;@Service
public class OrderService {@Autowiredprivate RedisLock redisLock;public void createOrder(String orderId) {String lockKey = "order-lock:" + orderId;String requestId = UUID.randomUUID().toString();boolean locked = false;try {// 嘗試獲取鎖,設置過期時間為10秒locked = redisLock.tryLock(lockKey, requestId, 10, TimeUnit.SECONDS);if (locked) {// 獲得鎖成功,執行關鍵業務邏輯System.out.println("獲取鎖成功,開始處理訂單: " + orderId);// 模擬業務處理Thread.sleep(2000);} else {// 獲得鎖失敗,處理失敗邏輯System.out.println("獲取鎖失敗,稍后重試或執行其他策略");}} catch (Exception e) {e.printStackTrace();} finally {// 無論如何都嘗試釋放鎖,確保不會死鎖if (locked) {redisLock.releaseLock(lockKey, requestId);}}}
}

setIfAbsent方法

RedisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit) 是實現分布式鎖的核心方法,它對應Redis的命令:

SET key value NX EX timeout

關鍵點

  1. 原子性:該方法會原子性地完成三個操作:

    • 檢查key是否存在
    • 如果不存在,則設置key的值
    • 同時設置key的過期時間
  2. 防止死鎖

    • 必須設置過期時間,確保即使持有鎖的進程崩潰,鎖也會自動釋放
    • 過期時間不宜過短(避免業務未完成鎖就過期)或過長(影響性能)
  3. 唯一標識

    • value使用唯一的requestId(如UUID),用于標識鎖的持有者
    • 釋放鎖時必須驗證requestId,防止誤刪其他線程的鎖

釋放鎖的原子性問題

釋放鎖時不能簡單地直接刪除key,必須先驗證鎖的持有者:

// 錯誤示例(非原子操作,有競態條件)
if (redis.get(lockKey).equals(requestId)) {redis.delete(lockKey);
}// 正確方式:使用Lua腳本保證原子性
Long result = redisTemplate.execute(RELEASE_LOCK_SCRIPT, Collections.singletonList(lockKey), requestId);

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

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

相關文章

linux升級降級內核實驗

?實驗環境 vmware workstation 17 centos7.9 下載鏈接&#xff1a; https://vault.centos.org/7.9.2009/isos/x86_64/ ubuntu24.04 下載鏈接&#xff1a; https://old-releases.ubuntu.com/releases/24.04/ ?實驗目的 為了解決日常環境部署中某些驅動軟件依賴特定內…

華為云開始了“開發者空間 AI Agent 開發”活動

引言 今天在華為云App上偶然看到一個新活動&#xff1a;Developer Events_Developer Alliance-Huawei Cloud。這個活動要求開發者可結合自己的工作實踐&#xff0c;須在華為開發者空間內完成應用構建&#xff0c;應用構建類型和主題為AI Agent應用開發。 AI Agent平臺 華為開…

2025.6.26總結

今天和我做同一業務得同事進行了工作交接&#xff0c;主要給我講了怎么去執行自動化。包括性能自動化&#xff0c;API自動化&#xff0c;UI自動化&#xff0c;除了UI自動化要寫些代碼&#xff0c;其他跑得話也就在工具上配個參數&#xff0c;就是個搬磚得活&#xff0c;沒太大技…

ip網絡基礎

交換機工作原理&#xff1a; 自主學習mac地址并成mac地址表 根據mac地址表再進行單播、廣播轉發 主機通信原理&#xff08;局域網&#xff09;&#xff1a; 需要了解arp協議 拓撲圖&#xff1a; 首先&#xff0c;我們觀察icmp數據包&#xff0c;發現缺少目標mac地址&#…

AI大模型如何重塑軟件開發流程?

文章目錄 每日一句正能量前言一、AI大模型的定義與特點&#xff08;一&#xff09;定義&#xff08;二&#xff09;特點 二、AI大模型在軟件開發中的應用場景&#xff08;一&#xff09;代碼自動生成&#xff08;二&#xff09;智能測試&#xff08;三&#xff09;需求分析與設…

Kafka與RabbitMQ相比有什么優勢?

大家好&#xff0c;我是鋒哥。今天分享關于【Kafka與RabbitMQ相比有什么優勢&#xff1f;】面試題。希望對大家有幫助&#xff1b; Kafka與RabbitMQ相比有什么優勢&#xff1f; 超硬核AI學習資料&#xff0c;現在永久免費了&#xff01; Kafka與RabbitMQ在消息隊列的設計和應…

LeetCode 2090. 半徑為 k 的子數組平均值

題目鏈接 2090. 半徑為 k 的子數組平均值 題目描述 給定一個下標從 0 開始的整數數組 nums 和整數 k&#xff0c;構建并返回一個長度為 n 的數組 avgs&#xff0c;其中 avgs[i] 表示以下標 i 為中心、半徑為 k 的子數組的平均值。具體規則如下&#xff1a; 無效位置&#x…

深入理解C++11原子操作:從內存模型到無鎖編程

文章目錄 C并發編程的新紀元內存模型基礎&#xff1a;可見性與有序性數據競爭的根源happens-before關系memory_order枚舉詳解1. memory_order_relaxed2. memory_order_acquire/memory_order_release3. memory_order_seq_cst 原子操作詳解std::atomic模板核心原子操作1. 讀取與存…

DQL-1-基礎查詢

基礎查詢 DQL-1-基礎查詢 基礎查詢DQL - 介紹DQL - 語法DQL - 基本查詢案例 DQL - 介紹 SQL 英文全稱是 Data Query Language, 數據查詢語言, 用來查詢數據庫中表的記錄 查詢關鍵字: SELECT DQL - 語法 SELECT 字段列表FROM 表名列表WHERE條件列表GROUP BY分組字段列表HAVI…

Prompt 精通之路(七)- 你的終極 AI 寶典:Prompt 精通之路系列匯總

你的終極 AI 寶典&#xff1a;Prompt 精通之路系列匯總 標簽&#xff1a; #Prompt指南 #AI學習資源 #速查手冊 #ChatGPT #系列總結 &#x1f680; Prompt 精通之路&#xff1a;系列文章導航 第一篇&#xff1a;AI 時代的新語言&#xff1a;到底什么是 Prompt&#xff1f;為什么…

P27:RNN實現阿爾茨海默病診斷

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 一、過程解讀 PyTorch 實戰&#xff1a;阿爾茨海默病數據預測模型 今天&#xff0c;我將帶大家一起探索一個基于 PyTorch 的深度學習小項目——利用 RNN 模…

HakcMyVM-Arroutada

信息搜集 主機發現 ┌──(kali?kali)-[~] └─$ nmap -sn 192.168.21.0/24 Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-01 07:13 EDT Nmap scan report for 192.168.21.11 Host is up (0.00062s latency). MAC Address: 08:00:27:4E:CC:FB (PCS Systemtechnik/Or…

TEXT Submitting Solutions

前言 USACO 訓練項目配備了一個自動評分系統&#xff0c;用于批改你的作業題目。你可以直接在題目頁面提交你的程序&#xff1b;系統會對程序進行編譯和評分&#xff0c;幾秒鐘內就能將結果反饋給你。 支持的語言有 C、C&#xff08;含 C11 和 C14&#xff09;、PASCAL、Pyth…

Reactor 瞬態錯誤

在響應式編程中&#xff0c;retryWhen 操作符通過 RetrySignal 接口提供了對重試行為的精細控制&#xff0c;特別是在處理 瞬態錯誤&#xff08;transient errors&#xff09; 時。瞬態錯誤是指那些在一段時間內發生&#xff0c;但隨后會自行恢復的錯誤&#xff0c;例如網絡請求…

基于 SpringBoot+Vue.js+ElementUI 的小型超市商品管理系統設計與實現7000字論文設計

摘要 本論文設計并實現了一個基于 SpringBoot、Vue.js 和 ElementUI 的小型超市商品管理系統。該系統旨在為小型超市提供一個高效、便捷的商品管理解決方案&#xff0c;實現商品信息的錄入、查詢、修改、刪除等功能&#xff0c;同時支持庫存管理、銷售統計等業務需求。論文首先…

Kerberos 認證協議解析

文章目錄 概述核心概念認證流程階段一&#xff1a;Client -> AS&#xff0c;獲取 TGT階段二&#xff1a;Client -> TGS&#xff0c;獲取服務票據階段三&#xff1a;Client -> Server&#xff0c;請求服務 核心安全機制優缺點分析優勢局限性 實踐與排錯關鍵配置 (krb5.…

【設計模式07】適配器

前言 實現目標&#xff0c;組合源&#xff0c;寫個適配方法&#xff0c;適用于沒辦法改變源&#xff0c;但又想實現目標類。我暫時還沒使用到過&#xff0c;但感覺用處還是蠻大的 UML類圖 代碼示例 package com.sw.learn.pattern.C_structre.a_adapter;public class Main {//…

SPI、I2C和UART三種串行通信協議的--------簡單總結

目錄 一、3種協議的對比二、典型應用場景三、選型建議 以下是SPI、I2C和UART三種串行通信協議的對比分析及適用場景總結&#xff1a; 一、3種協議的對比 . 對比其他接口 特性ICSPIUART信號線數量2&#xff08;SCL SDA&#xff09;4&#xff08;SCK MOSI MISO SS/CS&…

VUE admin-element 后臺管理系統三級菜單實現緩存

VUE admin-element 后臺管理系統三級菜單實現緩存 框架無法直接實現三級菜單頁面緩存&#xff0c;原因是由于直接緩存時沒有把上級路由文件名稱緩存進去&#xff0c;所以在框架基礎上參考部分文章進行了一些改造 菜單文件&#xff0c;三級菜單引用文件路徑修改&#xff0c;在…

【筆記】Windows 安裝 Gemini CLI

2025 年 07 月 02 日 Windows 安裝 Gemini CLI google-gemini/gemini-cli&#xff1a;一個開源的 AI 代理&#xff0c;可將 Gemini 的強大功能直接引入您的終端。 一、前置條件 系統要求&#xff1a;Windows 7 及以上版本。 Node.js 環境&#xff1a;Gemini CLI 基于 Node.js …