Redis事務

一:Redis的事務

  Redis通過MULTIEXECDISCARD 和 WATCH 命令來實現事務的支援,通過它們我們可以一步操作執行一組命令,而且確保了兩個重要的特徵如下

1.所有的命令在一個事務中可確保順序執行,切不會被其它執行緒打斷(插入其它指令)。

2.確保所有的命令要麼全部執行要麼一個也不執行。注意並不能保證每個任務都執行成功,而且失敗的命令也不能回滾事務。

二:使用方法

步驟1: 開啟事務   MULTI

步驟2: 執行命令   command1 command2 ….

步驟3: 執行事務   EXEC  或 DISCARD

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR foo
QUEUED
127.0.0.1:6379> INCR bar
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1

備註:exec返回一個數組對象,數組的每個對象順序對應每個執行的命令

三:事務的失敗分析

  通常一個事務的失敗原因主要可分為兩類

類1:命令如隊(queue)失敗,即在EXEC命令調用之前失敗,失敗的原因多為命令-參數錯誤,或者是記憶體溢出

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr a b c
(error) ERR wrong number of arguments for 'incr' command

類2:EXEC命令調用之後失敗。注意一組命令其中一個命令失敗,並不會影響該命令後的其它命令的執行。

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a abc
QUEUED
127.0.0.1:6379> lpop a
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value

 

四:WATCH命令實現樂觀鎖

      WATCH通過check-and-set (CAS) 即檢查然後設置的機制來實現事務的回滾特性,即被WATCHed的屬性在執行事務之前會檢查該屬性值是否被其它執行緒改變,如果改變事務執行失敗,否則繼續。

通過例子分析:有如下業務

val = GET mykey  //步驟1:先獲取屬性值  若此時mykey的值為1
val = val + 1    //步驟2:給值加1 
SET mykey $val //步驟3:重新賦值熟悉

若有2個執行緒同時執行以上程式碼,其結果mykey的值只能加1即值為2,(兩個執行緒應該為3??)

我們可以通過WATCH命令監控mykey,即當其它或當前執行緒修改了mykey屬性的值,事務執行失敗

127.0.0.1:6379> set mykey 2
OK
127.0.0.1:6379> get mykey
"2"
127.0.0.1:6379> WATCH mykey   #監控mykey
OK
127.0.0.1:6379> get mykey     #查看mykey
"2"
127.0.0.1:6379> incr mykey    #重新賦值mykey  加1
(integer) 3
127.0.0.1:6379> MULTI         #開啟事務
OK
127.0.0.1:6379> set mykey 4   #重新賦值mykey
QUEUED
127.0.0.1:6379> exec          #執行事務
(nil)                         #執行失敗
127.0.0.1:6379> get mykey
"3"

備註:官方文檔上說當前連接對watched屬性操作不會影響事務,好像不是,這裡有對這個疑問的討論//github.com/antirez/redis-doc/issues/734

備註:UNWATCH指令,顧名思義即WATCH對立指令,即停止對某個屬性的監控,exec和discard指令都會調用unwatch指令,我們也可以手動調用該指令。

思考:WATCH是什麼?它是EXEC命令執行的條件,即被監控的屬性沒有被修改過為TURE,否則為FALSE

五:Redis腳本和事務

  Redis script(Redis腳本)是事務定義的,所以任何在事務中做的事情你都可以通過腳本完成,而且腳本更快和簡單

參考://redis.io/topics/transactions

Tags: