[redis學習筆記]五、Redis事務的使用

Redis的事務

概述

可以以此執行多個命令,本質上是一組命令的集合。一個事務中的所有命令多會序列化,按順序地串行化執行而不會被其他命令插入,不許加塞。

簡單地說,就是將一系列的命令按順序地加入到一個隊列中,一次性地、順序地、排他地執行這些命令。

常用命令

在這裏插入圖片描述

使用

步驟大致爲:multi(開啓事務)–>一系列的命令–>exec/discard(執行事務或放棄執行事務)

正常執行
## 開啓事務
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
## 執行事務
127.0.0.1:6379> EXEC
1) OK
2) OK
3) "v1"

可以發現,一系列的命令只是入隊QUEUED,而並沒有立即執行,而是等待EXEC時才執行

取消事務
## 開啓事務
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> get k4
QUEUED
## 取消事務
127.0.0.1:6379> DISCARD
OK
## 由於事務被取消,命令未被執行 所以k4沒有值
127.0.0.1:6379> get k4
(nil)

注意:redis統一事務中執行若干命令,並不能保證原子性

  1. 類比Java異常,如果是檢查異常,在編碼中未拋出時,系統會報錯。同理,在redis事務中,某個命令由於redis語法錯誤執行失敗,那麼該事務下的所有命令均執行失敗。

    127.0.0.1:6379> FLUSHDB
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set k1 v1
    QUEUED
    127.0.0.1:6379> set k2 v2
    QUEUED
    ## 語法錯誤 拋出異常信息
    127.0.0.1:6379> set k3
    (error) ERR wrong number of arguments for 'set' command
    ## 執行事務時發現有錯,事務被取消
    127.0.0.1:6379> EXEC
    (error) EXECABORT Transaction discarded because of previous errors.
    ## 其他正常命令的執行也被取消
    127.0.0.1:6379> get k2
    (nil)
    127.0.0.1:6379> get k1
    (nil)
    
  2. 類比Java編譯時異常,在redis事務中,某個命令因爲參數不合法等問題導致了錯誤,那麼該事務下只會影響當前命令的執行結果,不會影響其他命令的正常執行。

    127.0.0.1:6379> FLUSHDB
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set k1 abcd
    QUEUED
    ## 參數不合法  字符串不能執行+1操作 但是這屬於編譯異常 這裏系統未檢出錯誤 直接入隊
    127.0.0.1:6379> INCR k1
    QUEUED
    127.0.0.1:6379> set k2 v2
    QUEUED
    127.0.0.1:6379> get k1
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    ## 執行時報錯參數問題,但是沒有影響其他命令的正常執行
    2) (error) ERR value is not an integer or out of range
    3) OK
    4) "abcd"
    127.0.0.1:6379> get k1
    "abcd"
    127.0.0.1:6379> get k2
    "v2"
    
watch監控

watch監控類似於樂觀鎖的機制,監控了某key,在事務中真正執行時發現該key可能被其他客戶端修改了,那麼當前事務執行失敗。需要重新監控該key,直至監控時候key的數據跟執行事務時key的數據均一致方可

悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,

樂觀鎖策略:提交版本必須大於記錄當前版本才能執行更新

正常使用

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
## 同時監控兩個key
127.0.0.1:6379> WATCH k1 k2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v11
QUEUED
127.0.0.1:6379> set k2 v22
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) "v11"
4) "v22"

異常情況

模擬監控key後,key被其他客戶端修改。

在這裏插入圖片描述

說明:監控了兩個key,分別是k1,k2。但是在事務執行時,k1的值被其他客戶端修改過,k1的值相當於watch時被修改過。因此事務執行失敗。響應結果nil

這種情況,只能重新watch,力求key是最新的數據。比如下面這次 就執行成功了

127.0.0.1:6379> WATCH k1 k2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v11
QUEUED
127.0.0.1:6379> set k2 v22
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) "v11"
unwatch

取消監控,同樣地,一旦事務執行完成,之前加到事務上某key的監控鎖也會被取消掉。

在這裏插入圖片描述

說明:監控了k1,後來又取消對k1的監控了。在事務執行前,對k1的值進行修改,對事務的正常執行沒有影響,k1的值變爲v11。因爲redis是單線程的,這裏推斷k1值的變化是:v1->v01->v11

watch總結

watch指令類似於樂觀鎖,事務提交時,如果key的值已被別的客戶端改變,比如某key被別的客戶端修改過,那麼整個事務隊列都不會被執行。

通過WATCH命令在事務執行之前監控了多個Keys(如上面的例子),倘若在WATCH之後有任何Key的值發生了變化,EXEC命令執行的事務都將被放棄,同時返回nil應答以通知調用者事務執行失敗。

總結

事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。

事務隊列中的命令沒有提交之前都不會實際的被執行,所以也就不會有隔離級別的問題。

不保證嚴格上的原子性操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章