事務是應用程式中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。
atomic(原子性):
一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。
consistency(一緻性):
事務執行的結果必須是使資料庫從一個一緻性狀态變到另一個一緻性狀态。
isolation(隔離性):
一個事務的執行不能其它事務幹擾。事務允許多個使用者對同一個資料進行并發通路,而不破壞資料的正确性和完整性。
durability(持久性):
也一個事務一旦送出,它對資料庫中的資料的改變就應該是永久性的。接下來的其它操作或故障不應該對其執行結果有任何影響。
redis對事務 的支援比較簡單。
redis 是單程序程式,并且它保證在執行事務時,不會對事務進行中斷,事務可以運作直到執 行完所有事務隊列中的指令為止。是以,redis 的事務支援隔離性。
實作事務的指令:
multi 标記一個事務塊的開始。
exec 執行所有事務塊内的指令。
discard 取消事務,放棄執行事務塊内的所有指令。
unwatch 取消 watch 指令對所有 key 的監視。
watch key [key ...]
監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他指令所改動,那麼事務将被打斷。
redis事務不支援復原。
redis使用 check-and-set 操作實作樂觀鎖。
watch 指令可以為 redis 事務提供 check-and-set (cas)行為。
類似java中的compareandset機制,被 watch 的鍵會被監視,并會發覺這些鍵是否被改動過了。
如果有至少一個被監視的鍵在 exec 執行之前被修改了, 那麼整個事務都會被取消, exec 傳回空多條批量回複(null multi-bulk reply)來表示事務已經失敗。
舉個例子, 假設我們需要原子性地為某個值進行增 1 操作(假設 incr 不存在)。
首先我們可能會這樣做:
1
2
3
<code>val </code><code>=</code> <code>get mykey</code>
<code>val </code><code>=</code> <code>val </code><code>+</code> <code>1</code>
<code>set</code> <code>mykey $val</code>
上面的這個實作在隻有一個用戶端的時候可以執行得很好。 但是, 當多個用戶端同時對同一個鍵進行這樣的操作時, 就會産生競争條件。
舉個例子, 如果用戶端 a 和 b 都讀取了鍵原來的值, 比如 10 , 那麼兩個用戶端都會将鍵的值設為 11 , 但正确的結果應該是 12 才對。
有了 watch , 我們就可以輕松地解決這類問題了:
4
5
6
7
<code>watch mykey</code>
<code>multi</code>
<code>exec</code>
使用上面的代碼, 如果在 watch 執行之後, exec 執行之前, 有其他用戶端修改了 mykey 的值, 那麼目前用戶端的事務就會失敗。 程式需要做的, 就是不斷重試這個操作, 直到沒有發生碰撞為止。
樂觀鎖是一種非常強大的鎖機制,在很多地方都有應用。 redis中大多數情況下, 不同的用戶端會通路不同的鍵, 碰撞的情況一般都很少, 是以通常并不需要進行重試。