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

分布式鎖詳解以及Spring?Boot實戰(zhàn)示例代碼

 更新時間:2025年09月03日 09:25:02   作者:老張還是少年  
在分布式系統(tǒng)中,使用分布式鎖是保證共享資源獨占性的重要方式,這篇文章主要介紹了分布式鎖詳解及Spring?Boot實戰(zhàn)的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

在分布式系統(tǒng)中,多個服務實例可能同時操作共享資源(如數(shù)據(jù)庫中的同一訂單、庫存記錄),若缺乏協(xié)調機制,會導致數(shù)據(jù)不一致(如超賣、重復下單)。分布式鎖正是解決這類問題的核心技術,它能保證同一時間只有一個服務實例執(zhí)行特定臨界區(qū)代碼。

一、分布式鎖的核心特性

一個可靠的分布式鎖需滿足以下特性:

  • 互斥性:任意時刻只有一個線程持有鎖。
  • 安全性:鎖只能被持有它的線程釋放。
  • 可用性:即使部分節(jié)點故障,鎖仍能正常獲取和釋放。
  • 防死鎖:避免因線程崩潰導致鎖永久無法釋放。
  • 冪等性:重復獲取 / 釋放鎖不會產(chǎn)生副作用。

二、分布式鎖的實現(xiàn)方案及原理

常見實現(xiàn)方式包括基于數(shù)據(jù)庫、Redis、ZooKeeper 等,不同方式的原理各有不同。

1. 基于數(shù)據(jù)庫的分布式鎖

原理:利用數(shù)據(jù)庫的唯一索引或悲觀鎖來實現(xiàn)。例如,創(chuàng)建一張鎖表,包含資源標識、持有線程標識、過期時間等字段,給資源標識字段創(chuàng)建唯一索引。當需要獲取鎖時,向表中插入一條記錄,若插入成功則表示獲取到鎖;釋放鎖時,刪除該記錄。為防止死鎖,可定期清理過期未釋放的鎖。

優(yōu)缺點

  • 優(yōu)點:實現(xiàn)簡單,無需額外中間件。
  • 缺點:性能較差,數(shù)據(jù)庫壓力大;易出現(xiàn)鎖表問題;不支持鎖自動續(xù)期等高級特性。

2. 基于 Redis 的分布式鎖

原理:利用 Redis 的SET命令的原子性。核心命令如下:

# 僅當key不存在時設置值,過期時間10秒,返回OK表示獲取鎖成功

SET lock:resource true NX PX 10000
  • NX:僅在鍵不存在時才設置(保證互斥性)。
  • PX 10000:設置鍵的過期時間為 10 秒(防死鎖)。

釋放鎖時,需通過 Lua 腳本保證原子性,先判斷鎖是否由當前線程持有,再刪除鎖:

if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

優(yōu)缺點

  • 優(yōu)點:性能高,操作簡單;支持過期時間設置。
  • 缺點:在 Redis 集群環(huán)境下,可能存在主從同步延遲導致的鎖丟失問題;需自行處理鎖續(xù)期等問題。

由于 Redis 的高性能和易用性,它成為分布式鎖的主流選擇,本文后續(xù)重點介紹基于 Redis 的分布式鎖實現(xiàn)。

3. 基于 ZooKeeper 的分布式鎖

原理:利用 ZooKeeper 的節(jié)點特性和 Watcher 機制。ZooKeeper 的節(jié)點分為持久節(jié)點、臨時節(jié)點、持久順序節(jié)點、臨時順序節(jié)點。分布式鎖通常使用臨時順序節(jié)點,當需要獲取鎖時,在指定節(jié)點下創(chuàng)建一個臨時順序節(jié)點,然后判斷當前節(jié)點是否為序號最小的節(jié)點,若是則獲取到鎖;若不是,則監(jiān)聽序號比當前節(jié)點小的最后一個節(jié)點,當該節(jié)點被刪除時,重新判斷。釋放鎖時,刪除創(chuàng)建的臨時節(jié)點,由于是臨時節(jié)點,當持有鎖的線程崩潰時,節(jié)點會自動刪除,避免死鎖。

優(yōu)缺點

  • 優(yōu)點:可靠性高,不存在鎖丟失問題;支持公平鎖;自帶 Watcher 機制,可實現(xiàn)鎖的自動釋放和喚醒。
  • 缺點:性能相對 Redis 較低;部署和維護成本高。

三、Spring Boot 集成分布式鎖的相關依賴及對比

1. 基于 Redis 的依賴

  • spring-boot-starter-data-redis
    • 提供了 Redis 的基本操作模板(RedisTemplate),可用于手動實現(xiàn)分布式鎖。
    • 需自行處理鎖的獲取、釋放、續(xù)期等邏輯,實現(xiàn)相對復雜,但靈活性高。
  • redisson-spring-boot-starter
    • 是 Redis 官方推薦的 Java 客戶端,內置了分布式鎖的完整實現(xiàn),支持自動續(xù)期、公平鎖、可重入鎖等高級特性。
    • 封裝了復雜的底層邏輯,使用簡單,適合生產(chǎn)環(huán)境。

2. 基于 ZooKeeper 的依賴

  • spring-cloud-starter-zookeeper-discovery
    • 主要用于服務發(fā)現(xiàn),但也可借助 ZooKeeper 客戶端操作 ZooKeeper 實現(xiàn)分布式鎖。
    • 需要自行基于 ZooKeeper 的 API 實現(xiàn)鎖的邏輯,較為繁瑣。
  • curator-recipes
    • 是 ZooKeeper 的客戶端框架,提供了分布式鎖等常用功能的封裝,如 InterProcessMutex 等類可直接用于實現(xiàn)分布式鎖。
    • 簡化了 ZooKeeper 分布式鎖的實現(xiàn),可靠性高。

3. 依賴對比

依賴

基于中間件

特點

適用場景

spring-boot-starter-data-redis

Redis

基礎操作支持,需自行實現(xiàn)鎖邏輯

簡單場景,對靈活性要求高

redisson-spring-boot-starter

Redis

內置完整鎖實現(xiàn),支持高級特性

生產(chǎn)環(huán)境,復雜業(yè)務場景

spring-cloud-starter-zookeeper-discovery

ZooKeeper

主要用于服務發(fā)現(xiàn),鎖實現(xiàn)需自行開發(fā)

已使用 ZooKeeper 做服務發(fā)現(xiàn),簡單鎖場景

curator-recipes

ZooKeeper

封裝了分布式鎖功能,可靠性高

對鎖可靠性要求高的場景

四、Spring Boot 集成 Redis 分布式鎖實戰(zhàn)

1. 環(huán)境準備

pom.xml 依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>org.redisson</groupId> <!-- 推薦使用Redisson簡化鎖操作 -->
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.3</version>
</dependency>

Redis 配置(application.yml)

spring:
  redis:
    host: localhost
    port: 6379
    database: 0
    timeout: 3000ms

2. 基于 Redisson 的分布式鎖實現(xiàn)

Redisson 是 Redis 官方推薦的 Java 客戶端,內置了分布式鎖的完整實現(xiàn),支持自動續(xù)期、公平鎖、可重入鎖等高級特性。

分布式鎖工具類

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLock {

    private final RedissonClient redissonClient;

    public RedisDistributedLock(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 獲取分布式鎖
     * @param lockKey 鎖標識
     * @param waitTime 等待時間(獲取鎖的最大等待時長)
     * @param leaseTime 鎖持有時間(自動釋放時間)
     * @return 鎖對象
     */
    public RLock lock(String lockKey, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 嘗試獲取鎖,最多等待waitTime,持有l(wèi)easeTime后自動釋放
            boolean isLocked = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            if (isLocked) {
                return lock;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return null;
    }

    /**
     * 釋放鎖
     * @param lock 鎖對象
     */
    public void unlock(RLock lock) {
        if (lock != null && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

3. 業(yè)務場景示例:庫存扣減

Service 層代碼

import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class InventoryService {

    @Resource
    private RedisDistributedLock distributedLock;
    @Resource
    private InventoryMapper inventoryMapper;  // 假設已實現(xiàn)數(shù)據(jù)庫操作

    /**
     * 扣減商品庫存
     * @param productId 商品ID
     * @param quantity 扣減數(shù)量
     * @return 操作結果
     */
    public boolean deductInventory(Long productId, int quantity) {
        // 鎖標識:通常用業(yè)務資源唯一標識(如商品ID)
        String lockKey = "lock:inventory:" + productId;
        RLock lock = null;
        try {
            // 獲取鎖:最多等待3秒,持有10秒后自動釋放
            lock = distributedLock.lock(lockKey, 3, 10);
            if (lock == null) {
                // 獲取鎖失?。ㄈ绯瑫r)
                return false;
            }

            // 臨界區(qū)代碼:查詢庫存并扣減
            int currentStock = inventoryMapper.selectStockByProductId(productId);
            if (currentStock >= quantity) {
                inventoryMapper.updateStock(productId, currentStock - quantity);
                return true;
            } else {
                // 庫存不足
                return false;
            }
        } finally {
            // 確保鎖釋放
            distributedLock.unlock(lock);
        }
    }
}

五、關鍵注意事項

  • 鎖的粒度:鎖標識應精準到具體資源(如lock:order:123而非lock:order),避免鎖范圍過大導致性能瓶頸。
  • 過期時間設置:需大于業(yè)務執(zhí)行時間,Redisson 的watch dog機制會自動續(xù)期(默認每 30 秒續(xù)期一次)。
  • 異常處理:必須在finally塊中釋放鎖,避免因業(yè)務異常導致鎖泄漏。
  • 重試機制:獲取鎖失敗時可添加有限重試邏輯(如循環(huán) 3 次),提高成功率。

六、進階優(yōu)化方向

  • 公平鎖:通過redissonClient.getFairLock(lockKey)實現(xiàn),避免線程饑餓。
  • 紅鎖(RedLock):在多 Redis 節(jié)點環(huán)境中,通過多個實例獲取鎖提高可靠性(適合極高一致性場景)。
  • 緩存與數(shù)據(jù)庫一致性:結合本地鎖(synchronized)與分布式鎖,減少分布式鎖的使用頻率。

通過不同的分布式鎖實現(xiàn)方式和相關依賴,Spring Boot 應用可在分布式環(huán)境中安全地操作共享資源。在實際開發(fā)中,需根據(jù)業(yè)務場景和性能需求選擇合適的實現(xiàn)方式和依賴,Redisson 等成熟工具可大幅降低實現(xiàn)復雜度,建議在生產(chǎn)環(huán)境中優(yōu)先采用。

總結

到此這篇關于分布式鎖詳解以及Spring Boot實戰(zhàn)的文章就介紹到這了,更多相關分布式鎖及Spring Boot實戰(zhàn)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 解決idea 通過build project 手動觸發(fā)熱部署失敗的問題

    解決idea 通過build project 手動觸發(fā)熱部署失敗的問題

    在debug運行項目的過程中,并且保證(不添加方法,不修改方法名)一定的規(guī)則的情況下,可以通過build project 來手動熱部署項目,本文給大家介紹解決idea 通過build project 手動觸發(fā)熱部署失敗的問題,感興趣的朋友一起看看吧
    2023-12-12
  • java代碼實現(xiàn)編譯源文件

    java代碼實現(xiàn)編譯源文件

    這篇文章主要為大家詳細介紹了Java通過?JavaCompiler?實現(xiàn)編譯源文件的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2025-01-01
  • Java生產(chǎn)者和消費者例子_動力節(jié)點Java學院整理

    Java生產(chǎn)者和消費者例子_動力節(jié)點Java學院整理

    生產(chǎn)者-消費者(producer-consumer)問題,也稱作有界緩沖區(qū)(bounded-buffer)問題,兩個進程共享一個公共的固定大小的緩沖區(qū)。下文通過實例給大家介紹java生產(chǎn)者和消費者,感興趣的朋友一起學習吧
    2017-05-05
  • Java的HashMap源碼解析

    Java的HashMap源碼解析

    這篇文章主要介紹了Java的HashMap源碼解析,HashMap是一個用于存儲Key-Value鍵值對的集合,每一個鍵值對是一個Node,后臺是用一個Node數(shù)組來存放數(shù)據(jù),這個Node數(shù)組就是HashMap的主干,需要的朋友可以參考下
    2023-11-11
  • 通過Java實現(xiàn)添加或刪除PDF中的附件

    通過Java實現(xiàn)添加或刪除PDF中的附件

    當我們在制作PDF文件或者PPT演示文稿的時候,為了讓自己的文件更全面詳細,就會在文件中添加附件。本文為大家整理了Java實現(xiàn)添加或刪除PDF中的附件的方法,需要的可以參考下
    2023-01-01
  • Java 設計模式之適配器模式詳解

    Java 設計模式之適配器模式詳解

    設計模式(Design pattern)是一套被反復使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設計經(jīng)驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
    2021-11-11
  • 原理分析SonarQube中IdentityProvider賬戶互斥現(xiàn)象

    原理分析SonarQube中IdentityProvider賬戶互斥現(xiàn)象

    這篇文章主要為大家介紹分析SonarQube中IdentityProvider賬戶互斥現(xiàn)象原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-02-02
  • 關于mybatis if else if 條件判斷SQL片段表達式取值和拼接問題

    關于mybatis if else if 條件判斷SQL片段表達式取值和拼接問題

    這篇文章主要介紹了mybatis if else if 條件判斷SQL片段表達式取值和拼接,文章通過自己真實使用的例子給大家詳細介紹,需要的朋友可以參考下
    2021-09-09
  • java繪制國際象棋與中國象棋棋盤

    java繪制國際象棋與中國象棋棋盤

    這篇文章主要為大家詳細介紹了java繪制國際象棋與中國象棋棋盤,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • SpringCloud中的Ribbon負載均衡詳細解讀

    SpringCloud中的Ribbon負載均衡詳細解讀

    這篇文章主要介紹了SpringCloud中的Ribbon負載均衡詳細解讀,當系統(tǒng)面臨大量的用戶訪問,負載過高的時候,通常會增加服務器數(shù)量來進行橫向擴展(集群),多個服務器的負載需要均衡,以免出現(xiàn)服務器負載不均衡,部分服務器負載較大,部分服務器負載較小的情況,需要的朋友可以參考下
    2023-11-11

最新評論

泾源县| 将乐县| 和龙市| 潼南县| 河北省| 长海县| 淅川县| 宁阳县| 潮州市| 中牟县| 章丘市| 山西省| 交口县| 四平市| 盐山县| 霍城县| 吉木萨尔县| 咸宁市| 金溪县| 阳高县| 博乐市| 甘孜县| 宣城市| 南安市| 澄城县| 理塘县| 海伦市| 共和县| 石首市| 宁武县| 林周县| 潜山县| 泾阳县| 库伦旗| 兴安县| 历史| 红安县| 车险| 临武县| 赞皇县| 高密市|