標籤:io ar 使用 sp java strong on 資料 問題
Redis的事務基於四個命令:
建立事務
Redis的事務從一個MULTI命令開始,MULTI總會命令返回"ok"。
接著就可以開始輸入操作資料,每一條操作命令都會進入隊列。
最後執行EXEC,在隊列中的命令得到執行。
比如這樣:
> MULTIOK> INCR fooQUEUED> INCR barQUEUED> EXEC1) (integer) 12) (integer) 1
如果事務中出現錯誤怎麼辦?
首先我們將事務中的錯誤分為兩類:
- 進入隊列前發現錯誤,比如命令的語法錯誤。
- EXEC執行後發現錯誤,比如對同一個key執行的兩次不同資料類型的操作。
第一種很好理解,就像上面給出的例子中,成功進入隊列後會立馬返回"QUEUED"。
如果沒能進入隊列,則整個事務都會失效,提示"Transaction discarded because of previous errors."
關於EXEC執行後出現的錯誤,凡是成功進入隊列的都會被執行,即便同一事物中有執行失敗的命令,其餘的命令都會得到執行。
這讓那些用過關係型資料庫的人們感到詫異, 為什麼Redis不支援roll back?
對此官網的兩點說法:
Redis commands can fail only if called with a wrong syntax (and the problem is not detectable during the command queueing), or against keys holding the wrong data type: this means that in practical terms a failing command is the result of a programming errors, and a kind of error that is very likely to be detected during development, and not in production.
Redis is internally simplified and faster because it does not need the ability to roll back.
有人說不支援roll back會引發各種bug。但需要明白的是,roll back不是用來解決編程層面上的錯誤的。
而且,導致命令失敗只有兩種可能:
鑒於此,roll back幾乎沒有任何意義,Redis更傾向於不支援roll back而是保持簡潔和高效。
丟棄事務
DISCARD可以用作丟棄當前事務,並將串連狀態恢複為正常狀態。
使用方法如下:
> SET foo 1OK> MULTIOK> INCR fooQUEUED> DISCARDOK> GET foo"1"
原子性
check-and-set(CAS)之類的操作往往會出現竟態條件。
Redis提供了WATCH用於觀察key的變化。
當一個被觀察的key在EXEC執行前變化時,整個事務會終止並返回Nil,對該key的觀察也會結束。
剛接觸WATCH的時候,感覺這種處理方式很晦澀。不能加個顯示鎖什麼的嗎?
好在官網給出了充分的說明,先假設Redis沒有提供INCR,我們現在要類比一個遞增操作:
val = GET mykeyval = val + 1SET mykey $val
一個client進行該操作時是沒有問題,但多個client一起進行該操作時會出現竟態條件。
比如A和B兩個client同時進行了GET mykey,得到的都是10,因此兩次執行的結果是11而不是12。
而加入WATCH後:
WATCH mykeyval = GET mykeyval = val + 1MULTISET mykey $valEXEC
如果WATCH和EXEC之間有其他的什麼東東改變了被觀察的key,該事務則會失敗。
如果希望本次事務執行成功則需要在迴圈中執行,當然,這也是一種locking方式。
事實上,多個client訪問同一key的衝突並不常見,看具體情況進行操作吧。
相應地,也有UNWATCH可以用於釋放所有被觀察的key。
比如下面的例子中,事務內的INCR會成功執行:
WATCH keyUNWATCH keyMULTIINCR keyEXEC
Redis - 事務操作