Redis事務
一:Redis的事務
Redis通過MULTI, EXEC, DISCARD 和 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) 即檢查然後設置的機制來實現事務的回滾特性,即被WATCH
ed的屬性在執行事務之前會檢查該屬性值是否被其它執行緒改變,如果改變事務執行失敗,否則繼續。
通過例子分析:有如下業務
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