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

JAVA實現(xiàn)redis分布式雙重加鎖的示例代碼

 更新時間:2024年10月21日 09:16:25   作者:執(zhí)鍵行天涯  
在高并發(fā)環(huán)境下,通過Redis分布式鎖實現(xiàn)數(shù)據(jù)唯一性校驗非常關(guān)鍵,為避免用戶數(shù)據(jù)重復(fù),可使用Redis鎖或集合數(shù)據(jù)結(jié)構(gòu)進行前置檢查,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

背景:在日常開發(fā)過程中,遇到了一個需求,比如有一個對象User(name,age、sex)有三個屬性,現(xiàn)在需要用戶新增接口中,防止此接口被多人同時請求訪問,產(chǎn)生了姓名&年齡相同的,還有年齡&性別相同的數(shù)據(jù);

此問題的考慮思路

如果一個線程調(diào)用用戶新增接口的時候,在業(yè)務(wù)中通過查詢數(shù)據(jù)庫中是否已有相關(guān)數(shù)據(jù),從而不拋出異常提示,不讓做保存到數(shù)據(jù)庫的操作;這種考慮是我們最常見的考慮內(nèi)容。還有個問題,如果是外部系統(tǒng),涉及的操作并發(fā)量特別的大,那調(diào)用這個接口的并發(fā)量也很大的話,單純在通過校驗庫中是否有重復(fù)的數(shù)據(jù)防止重復(fù)數(shù)據(jù)插入只能阻止一部分問題數(shù)據(jù)的入庫。如果同時有兩個用戶甲乙,填寫的姓名和年齡
(年齡和性別是同樣的考慮方法);此時從庫中查了,沒有已有的數(shù)據(jù),此時為了防止這兩個用戶甲乙操作的重復(fù)數(shù)據(jù)同時入庫的情況,我們就得加上一個分布式鎖了(如果在單體應(yīng)用中可以使用synchronized),分布式架構(gòu)中需要使用Redis分布式鎖或者Redission分布式鎖來實現(xiàn)相應(yīng)的控制了;

在設(shè)計分布式Redis鎖以避免在新增User時出現(xiàn)同name和age組合,或者同age和sex組合的情況,你需要構(gòu)建一個能夠唯一標識這些條件的key。由于Redis鎖通常用于確保操作的原子性,而你的需求是檢查并避免重復(fù)數(shù)據(jù),這里實際上可能更偏向于使用Redis的其它數(shù)據(jù)結(jié)構(gòu)(如集合、有序集合或哈希表)來輔助實現(xiàn),而不是僅僅使用單獨的key-value鎖

使用Redis的key-value鎖的基本思路

1.定義鎖的key:鎖的key應(yīng)該能夠唯一標識你想要保護的資源或操作。在你的場景中,由于涉及到多個字段的組合檢查,你可以考慮將這些
字段組合成一個字符串作為key。例如:

對于name和age的組合,可以使用user??name:{name}:age:{age}。

對于age和sex的組合,可以使用user??age:{age}:sex:{sex}。

2.設(shè)置鎖:在嘗試新增User之前,先嘗試設(shè)置這個鎖。如果鎖設(shè)置成功(即沒有其他進程或線程持有這個鎖),則繼續(xù)執(zhí)行檢查邏輯。

3.檢查并插入:在鎖的保護下,檢查數(shù)據(jù)庫中是否已經(jīng)存在具有相同name和age或age和sex組合的User。如果不存在,則執(zhí)行插入操作。

4.釋放鎖:無論操作成功還是失敗,最后都要釋放鎖,以便其他進程或線程可以獲取鎖并執(zhí)行操作。

結(jié)合Redis數(shù)據(jù)結(jié)構(gòu)實現(xiàn)避免重復(fù)

然而,更有效的方法可能是使用Redis的集合(Set)或有序集合(Sorted Set)來存儲已經(jīng)存在的組合,并檢查新組合是否已存在。

1.使用集合:

  • 對于name和age的組合,可以創(chuàng)建一個集合user:name_age,其中每個元素都是{name}:{age}的字符串。
  • 對于age和sex的組合,可以創(chuàng)建另一個集合user:age_sex,其中每個元素都是{age}:{sex}的字符串。
  • 在新增User時,先檢查相應(yīng)的集合中是否已經(jīng)存在該組合。如果不存在,則添加到集合中,并執(zhí)行數(shù)據(jù)庫插入操作。
    2.使用有序集合(如果需要按某種順序排序):
  • 類似于集合,但你可以為元素指定一個分數(shù)(score),以便按特定順序存儲和檢索元素。

注意事項

性能考慮:隨著集合中元素的增加,檢查操作可能會變慢。因此,你可能需要考慮使用哈希表或其他數(shù)據(jù)結(jié)構(gòu)來優(yōu)化查找性能。
事務(wù)性:確保檢查集合和插入數(shù)據(jù)庫的操作是原子性的,以防止在檢查之后但在插入之前發(fā)生數(shù)據(jù)變化。
鎖的超時:設(shè)置鎖的超時時間以防止死鎖。
鎖的粒度:根據(jù)你的應(yīng)用場景,你可能需要調(diào)整鎖的粒度。例如,如果操作非常頻繁,并且可以接受一定程度的重復(fù)檢查,則可以考慮放寬鎖的粒度或使用更輕量級的同步機制。

實現(xiàn)代碼

只避免 name和age的重復(fù)

下面的實現(xiàn)的一些代碼:希望能幫到大家理解思路。

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.core.ValueOperations;  
import org.springframework.stereotype.Service;  
  
import java.util.concurrent.TimeUnit;  
  
@Service  
public class UserService {  
  
    @Autowired  
    private RedisTemplate<String, String> redisTemplate;  
  
    // 假設(shè)的鎖過期時間  
    private static final long LOCK_EXPIRATION_TIME = 10L; // 10秒  
  
    // 嘗試獲取鎖  
    private boolean tryLock(String key) {  
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();  
        // 嘗試設(shè)置鎖,如果鍵不存在則設(shè)置成功,并設(shè)置過期時間  
        return opsForValue.setIfAbsent(key, "locked", LOCK_EXPIRATION_TIME, TimeUnit.SECONDS);  
    }  
  
    // 釋放鎖  
    private void releaseLock(String key) {  
        redisTemplate.delete(key);  
    }  
  
    // 新增User的邏輯  
    public void addUserIfNotExists(User user) {  
        String nameAgeLockKey = "user:lock:name:" + user.getName() + ":age:" + user.getAge();  
  
        // 嘗試獲取鎖  ,獲取鎖成功才會繼續(xù)執(zhí)行下面業(yè)務(wù)上的校驗
        if (tryLock(nameAgeLockKey)) {  
            try {  
                // 在這里執(zhí)行數(shù)據(jù)庫檢查(是否已存在同name和age)  
                
                // 如果不存在,則執(zhí)行插入操作  
  
                // 假設(shè)檢查通過,執(zhí)行插入操作(這里省略了具體的數(shù)據(jù)庫操作)  
                System.out.println("User added successfully");  
  
            } finally {  
                // 釋放鎖  
                releaseLock(nameAgeLockKey);  
            }  
        } else {  
            // 未能獲取鎖,可能是其他進程正在處理相同的組合  
            System.out.println("Failed to acquire lock(s), user addition may be in progress");  
        }  
    }  
  
    // ... 其他代碼 ...  
}

避免 name和age的和age和sex重復(fù):使用雙重的分布式鎖實現(xiàn):

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.core.ValueOperations;  
import org.springframework.stereotype.Service;  
  
import java.util.concurrent.TimeUnit;  
  
@Service  
public class UserService {  
  
    @Autowired  
    private RedisTemplate<String, String> redisTemplate;  
  
    // 假設(shè)的鎖過期時間  
    private static final long LOCK_EXPIRATION_TIME = 10L; // 10秒  
  
    // 嘗試獲取鎖  
    private boolean tryLock(String key) {  
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();  
        // 嘗試設(shè)置鎖,如果鍵不存在則設(shè)置成功,并設(shè)置過期時間  
        return opsForValue.setIfAbsent(key, "locked", LOCK_EXPIRATION_TIME, TimeUnit.SECONDS);  
    }  
  
    // 釋放鎖  
    private void releaseLock(String key) {  
        redisTemplate.delete(key);  
    }  
  
    // 新增User的邏輯  
    public void addUserIfNotExists(User user) {  
    	//加兩次鎖
        String nameAgeLockKey = "user:lock:name:" + user.getName() + ":age:" + user.getAge();  
        String ageSexLockKey = "user:lock:age:" + user.getAge() + ":sex:" + user.getSex();  
  
        // 嘗試獲取兩個鎖  
        if (tryLock(nameAgeLockKey) && tryLock(ageSexLockKey)) {  
            try {  
                // 在這里執(zhí)行數(shù)據(jù)庫檢查(是否已存在同name和age或同age和sex的User)  
                // 如果不存在,則執(zhí)行插入操作  
  
                // 假設(shè)檢查通過,執(zhí)行插入操作(這里省略了具體的數(shù)據(jù)庫操作)  
                System.out.println("User added successfully");  
  
            } finally {  
                // 釋放鎖  釋放兩次
                releaseLock(nameAgeLockKey);  
                releaseLock(ageSexLockKey);  
            }  
        } else {  
            // 未能獲取鎖,可能是其他進程正在處理相同的組合  
            System.out.println("Failed to acquire lock(s), user addition may be in progress");  
        }  
    }  
  
    // ... 其他代碼 ...  
}

雙重加鎖的 注意點上面的代碼示例簡化了錯誤處理和重試邏輯。在實際應(yīng)用中,你可能需要處理各種異常情況,例如Redis服務(wù)器不可用、鎖被意外刪除或過期等。此外,如果業(yè)務(wù)邏輯復(fù)雜或執(zhí)行時間較長,你可能需要考慮使用更高級的鎖機制,如Redis的發(fā)布/訂閱模式、Lua腳本或Redis的RedLock算法來確保鎖的安全性和可靠性。

另外,請注意,tryLock 方法中的 setIfAbsent 操作是原子的,這意味著它會在單個Redis命令中完成檢查和設(shè)置操作,從而避免了競態(tài)條件。但是,由于網(wǎng)絡(luò)延遲、Redis服務(wù)器性能等因素,多個客戶端仍可能幾乎同時嘗試獲取相同的鎖。因此,即使使用了鎖,也需要謹慎地設(shè)計你的業(yè)務(wù)邏輯和錯誤處理策略。

到此這篇關(guān)于JAVA實現(xiàn)redis分布式雙重加鎖的示例代碼的文章就介紹到這了,更多相關(guān)JAVA redis分布式雙重加鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot對數(shù)據(jù)庫用戶名和密碼進行加密的兩種方案

    SpringBoot對數(shù)據(jù)庫用戶名和密碼進行加密的兩種方案

    在當今互聯(lián)網(wǎng)時代,?數(shù)據(jù)庫安全的重要性不言而喻,作為Java開發(fā)的主流框架,Spring Boot項目通常需要連接數(shù)據(jù)庫,而數(shù)據(jù)庫的?用戶名和密碼作為最敏感的信息之一,所以本文給大家詳細介紹兩種主流的數(shù)據(jù)源配置加密方案,需要的朋友可以參考下
    2025-12-12
  • Java運行Python腳本的幾種方式小結(jié)

    Java運行Python腳本的幾種方式小結(jié)

    在跨語言編程中,有時候我們需要在 Java 應(yīng)用程序中執(zhí)行 Python 腳本,這可能是為了利用 Python 豐富的庫生態(tài)系統(tǒng),或者是為了在已有 Java 系統(tǒng)中集成一些 Python 特有的功能,本文給大家介紹了實現(xiàn)這幾種目標的方法,需要的朋友可以參考下
    2024-12-12
  • Springboot 跨域配置無效及接口訪問報錯的解決方法

    Springboot 跨域配置無效及接口訪問報錯的解決方法

    這篇文章主要介紹了Springboot 跨域配置無效及接口訪問報錯的解決方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • SpringBoot整合Druid數(shù)據(jù)源過程詳解

    SpringBoot整合Druid數(shù)據(jù)源過程詳解

    這篇文章主要介紹了SpringBoot整合Druid數(shù)據(jù)源過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • java自定義異常打印內(nèi)容詳解

    java自定義異常打印內(nèi)容詳解

    這篇文章主要為大家詳細介紹了java自定義異常打印內(nèi)容的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • SpringBoot3 響應(yīng)式網(wǎng)絡(luò)請求客戶端的實現(xiàn)

    SpringBoot3 響應(yīng)式網(wǎng)絡(luò)請求客戶端的實現(xiàn)

    本文主要介紹了SpringBoot3 響應(yīng)式網(wǎng)絡(luò)請求客戶端的實現(xiàn),文章詳細闡述了如何使用SpringBoot3的網(wǎng)絡(luò)請求客戶端進行HTTP請求和處理響應(yīng),并提供了示例代碼和說明,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • 兩個List集合取相同重復(fù)數(shù)據(jù)的方法

    兩個List集合取相同重復(fù)數(shù)據(jù)的方法

    今天小編就為大家分享一篇關(guān)于兩個List集合取相同重復(fù)數(shù)據(jù)的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java二進制運算符超詳細講解及擴展知識

    Java二進制運算符超詳細講解及擴展知識

    Java源碼中涉及到大量的二進制操作,非常的復(fù)雜,但非常的快速,下面這篇文章主要介紹了Java二進制運算符超詳細講解及擴展知識的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-09-09
  • 使用多種方式實現(xiàn)遍歷HashMap的方法

    使用多種方式實現(xiàn)遍歷HashMap的方法

    下面小編就為大家?guī)硪黄褂枚喾N方式實現(xiàn)遍歷HashMap的方法。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • java為何不能多繼承的原因詳解

    java為何不能多繼承的原因詳解

    多重繼承是一個子類從多個父類中繼承屬性和方法。C++, Common Lisp是時下支持多重繼承的流行語言。那java為何不能多繼承呢,下面小編帶大家來一起學(xué)習(xí)一下吧
    2019-06-06

最新評論

吉林省| 确山县| 阿巴嘎旗| 阿鲁科尔沁旗| 伊吾县| 怀柔区| 万盛区| 海宁市| 洛南县| 龙泉市| 临洮县| 乌拉特前旗| 邵阳市| 区。| 建瓯市| 武冈市| 陆丰市| 临泽县| 闽清县| 龙胜| 宁都县| 嘉祥县| 丰城市| 宜兰市| 哈巴河县| 新巴尔虎左旗| 班戈县| 刚察县| 潮安县| 邵阳县| 乌审旗| 个旧市| 信宜市| 保德县| 通江县| 霍山县| 邢台县| 沙洋县| 临夏县| 稷山县| 长兴县|