欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis如何使用樂觀鎖(CAS)保證數(shù)據(jù)一致性

 更新時間:2022年03月25日 11:41:04   作者:翹翹腳_蹦高高  
本文主要介紹了Redis如何使用樂觀鎖(CAS)保證數(shù)據(jù)一致性,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

場景

在 Redis 中經(jīng)常會存在這么一種情況,讀取某一個 key 的值,做一些業(yè)務(wù)邏輯處理,然后根據(jù)讀取到的值來計算出一個新的值,重新 set 進(jìn)去。

如果客戶端 A 剛讀取到 key 值,緊接著客戶端 B 就修改這個 key 的值,那么就會存在并發(fā)安全的問題。

問題模擬

假設(shè) Redis Server 有個鍵名為 test 的key,里面存放的是一個 json 數(shù)組 [1, 2, 3]。

下面讓我們模擬一下,客戶端 A 與 客戶端 B 同時訪問修改的情況,代碼如下:

客戶端 A:

class RedisClientA(username: String, password: String, host: String, port: Int) {
    val jedis: Jedis

    init {
        val pool = JedisPool(JedisPoolConfig(), host, port)
        jedis = pool.resource
        jedis.auth(username, password)
    }

    fun update(key: String) {
        val idStr = jedis.get(key)
        val idList = Json.decodeFromString<MutableList<Int>>(idStr)

        // 等待2秒,模擬業(yè)務(wù)
        TimeUnit.SECONDS.sleep(2L)

        idList.add(4)
        println("new id list: $idList")

        jedis.set(key, Json.encodeToString(idList))
    }

    fun getVal(key: String): String? {
        return jedis.get(key)
    }
}

fun main() {
    val key = "test"
    val redisClientA = RedisClientA("default", "123456", "127.0.0.1", 6379)
    redisClientA.update(key)
    val res = redisClientA.getVal(key)
    println("res: $res")
}

客戶端 B:

class RedisClientB(username: String, password: String, host: String, port: Int) {
    val jedis: Jedis

    init {
        val pool = JedisPool(JedisPoolConfig(), host, port)
        jedis = pool.resource
        jedis.auth(username, password)
    }

    fun update(key: String) {
        val idStr = jedis.get(key)
        val idList = Json.decodeFromString<MutableList<Int>>(idStr)

        idList.add(5)
        println("new id list: $idList")

        jedis.set(key, Json.encodeToString(idList))
    }

    fun getVal(key: String): String? {
        return jedis.get(key)
    }
}

fun main() {
    val key = "test"
    val redisClientB = RedisClientB("default", "123456", "127.0.0.1", 6379)
    redisClientB.update(key)
    val res = redisClientB.getVal(key)
    println("res: $res")
}

客戶端 A 阻塞了 2 秒,用來模擬耗時業(yè)務(wù)邏輯的處理。正在處理的時候,客戶端 B 訪問了 “test”,并增加了 id:5。

在客戶端 A 耗時業(yè)務(wù)邏輯處理完的時候,增加了 id:4,并且會覆蓋掉 id:5。

最終“test” 里的內(nèi)容最終如下:

CAS 來保證數(shù)據(jù)一致性

WATCH 命令可以為 Redis 事務(wù)提供 check-and-set(CAS)行為。被 WATCH 的鍵會被監(jiān)視,并會發(fā)覺這些鍵是否被改動過了。如果有至少一個被監(jiān)視的建在 EXEC 執(zhí)行之前被修改了,那么整個事務(wù)都會被取消,EXEC 返回空(Null replay)來表示事務(wù)執(zhí)行失敗。我們只需要重復(fù)操作,希望在這個時間段內(nèi)不會有新的競爭。這種形式的鎖被稱作樂觀鎖,它是一種非常強大的鎖機制。

那么 CAS 的方式如何實現(xiàn)呢?我們只需要把 RedisClientA 的 update() 方法中的代碼修改如下:

fun update(key: String) {
    var flag = true

    while (flag) {
        jedis.watch(key)

        val idStr = jedis.get(key)
        val idList = Json.decodeFromString<MutableList<Int>>(idStr)

        // 等待2秒,模擬業(yè)務(wù)
        TimeUnit.SECONDS.sleep(2L)

        val transaction = jedis.multi()
        idList.add(4)
        println("new id list: $idList")

        transaction.set(key, Json.encodeToString(idList))

        transaction.exec()?.let {
            flag = false
        }
    }

}

最終 “test” 的內(nèi)容如下:

可見我們通過使用 WATCH 和 TRANACTION 命令,采用 CAS 樂觀鎖的方式實現(xiàn)了數(shù)據(jù)的一致性。

到此這篇關(guān)于Redis如何使用樂觀鎖(CAS)保證數(shù)據(jù)一致性的文章就介紹到這了,更多相關(guān)Redis 樂觀鎖保證數(shù)據(jù)一致性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis常用數(shù)據(jù)類型命令實例匯總

    Redis常用數(shù)據(jù)類型命令實例匯總

    這篇文章主要介紹了Redis常用數(shù)據(jù)類型命令實例匯總,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • 詳解Redis集群搭建的三種方式

    詳解Redis集群搭建的三種方式

    Redis是一個開源的key-value存儲系統(tǒng),大部分互聯(lián)網(wǎng)企業(yè)都用來做服務(wù)器端緩存。Redis在3.0版本前只支持單實例模式,雖然支持主從模式、哨兵模式部署來解決單點故障,但是現(xiàn)在互聯(lián)網(wǎng)企業(yè)動輒大幾百G的數(shù)據(jù),沒法滿足業(yè)務(wù)的需求,所以Redis在3.0版本以后就推出了集群模式。
    2021-05-05
  • Redis?定長隊列探索及實踐

    Redis?定長隊列探索及實踐

    這篇文章主要介紹了Redis?定長隊列探索及實踐,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • Redis中3種特殊的數(shù)據(jù)類型(BitMap、Geo和HyperLogLog)

    Redis中3種特殊的數(shù)據(jù)類型(BitMap、Geo和HyperLogLog)

    這篇文章主要給大家介紹了關(guān)于Redis中3種特殊的數(shù)據(jù)類型(BitMap、GEOADD和GEODIST)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • Redis在項目中的使用(JedisPool方式)

    Redis在項目中的使用(JedisPool方式)

    項目操作redis是使用的RedisTemplate方式,另外還可以完全使用JedisPool和Jedis來操作redis,本文給大家介紹Redis在項目中的使用,JedisPool方式,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • redis集群規(guī)范詳解

    redis集群規(guī)范詳解

    這篇文章主要介紹了redis集群規(guī)范詳解,涉及節(jié)點失效檢測、集群狀態(tài)檢測、從節(jié)點選舉等相關(guān)內(nèi)容,比較詳細(xì),需要的朋友可以參考。
    2017-10-10
  • 一文快速搞懂Redis的幾種數(shù)據(jù)類型方式

    一文快速搞懂Redis的幾種數(shù)據(jù)類型方式

    這篇文章主要介紹了一文快速搞懂Redis的幾種數(shù)據(jù)類型方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 讓Redis在你的系統(tǒng)中發(fā)揮更大作用的幾點建議

    讓Redis在你的系統(tǒng)中發(fā)揮更大作用的幾點建議

    Redis在很多方面與其他數(shù)據(jù)庫解決方案不同:它使用內(nèi)存提供主存儲支持,而僅使用硬盤做持久性的存儲;它的數(shù)據(jù)模型非常獨特,用的是單線程。另一個大區(qū)別在于,你可以在開發(fā)環(huán)境中使用Redis的功能,但卻不需要轉(zhuǎn)到Redis
    2014-06-06
  • Redis設(shè)置database不生效的解決方案

    Redis設(shè)置database不生效的解決方案

    最近在做redis緩存設(shè)置的時候,發(fā)現(xiàn)即使已經(jīng)設(shè)置了database, 但是存數(shù)據(jù)的時候還是用的默認(rèn)0數(shù)據(jù)庫,所以本文就給大家介紹了Redis設(shè)置database不生效的解決方案,需要的朋友可以參考下
    2023-08-08
  • redis-benchmark并發(fā)壓力測試的問題解析

    redis-benchmark并發(fā)壓力測試的問題解析

    這篇文章主要介紹了redis-benchmark并發(fā)壓力測試的問題解析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01

最新評論