歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Redis 事務

Redis 事務

日期:2017/2/27 16:00:33   编辑:Linux教程
Redis對事務的支持目前還比較簡單。redis只能保證一個client發起的事務中的命令可以連續的執行,而中間不會插入其他client的命令。 由於redis是單線程來處理所有client的請求的所以做到這點是很容易的。一般情況下redis在接受到一個client發來的命令後會立即處理並 返回處理結果,但是當一個client在一個連接中發出multi命令有,這個連接會進入一個事務上下文,該連接後續的命令並不是立即執行,而是先放到一 個隊列中。當從此連接受到exec命令後,redis會順序的執行隊列中的所有命令。並將所有命令的運行結果打包到一起返回給client.然後此連接就 結束事務上下文。下面可以看一個例子
redis> multi
OK
redis> incr a
QUEUED
redis> incr b
QUEUED
redis> exec
1. (integer) 1
2. (integer) 1

從這個例子我們可以看到incr a ,incr b命令發出後並沒執行而是被放到了隊列中。調用exec後倆個命令被連續的執行,最後返回的是兩條命令執行後的結果
我們可以調用discard命令來取消一個事務。接著上面例子
redis> multi
OK
redis> incr a
QUEUED
redis> incr b
QUEUED
redis> discard
OK
redis> get a
"1"
redis> get b
"1"

可以發現這次incr a incr b都沒被執行。discard命令其實就是清空事務的命令隊列並退出事務上下文。
雖說redis事務在本質上也相當於序列化隔離級別的了。但是由於事務上下文的命令只排隊並不立即執行,所以事務中的寫操作不能依賴事務中的讀操作結果。看下面例子
redis> multi
OK
redis> get a
QUEUED
redis> get b
QUEUED
redis> exec
1. "1"
2. "1"

發現問題了吧。假如我們想用事務實現incr操作怎麼辦?可以這樣做嗎?
redis> get a
"1"
redis> multi
OK
redis> set a 2
QUEUED
redis> exec
1. OK
redis> get a,
"2"

結論很明顯這樣是不行的。這樣和 get a 然後直接set a是沒區別的。很明顯由於get a 和set a並不能保證兩個命令是連續執行的(get操作不在事務上下文中)。很可能有兩個client同時做這個操作。結果我們期望是加兩次a從原來的1變成3. 但是很有可能兩個client的get a,取到都是1,造成最終加兩次結果卻是2。主要問題我們沒有對共享資源a的訪問進行任何的同步
也就是說redis沒提供任何的加鎖機制來同步對a的訪問。
還好redis 2.1後添加了watch命令,可以用來實現樂觀鎖。看個正確實現incr命令的例子,只是在前面加了watch a
redis> watch a
OK
redis> get a
"1"
redis> multi
OK
redis> set a 2
QUEUED
redis> exec
1. OK
redis> get a,
"2"

watch 命令會監視給定的key,當exec時候如果監視的key從調用watch後發生過變化,則整個事務會失敗。也可以調用watch多次監視多個key.這 樣就可以對指定的key加樂觀鎖了。注意watch的key是對整個連接有效的,事務也一樣。如果連接斷開,監視和事務都會被自動清除。當然了 exec,discard,unwatch命令都會清除連接中的所有監視.
redis的事務實現是如此簡單,當然會存在一些問題。第一個問題是redis只能保證事務的每個命令連續執行,但是如果事務中的一個命令失敗了,並不回滾其他命令,比如使用的命令類型不匹配。
redis> set a 5
OK
redis> lpush b 5
(integer) 1
redis> set c 5
OK
redis> multi
OK
redis> incr a
QUEUED
redis> incr b
QUEUED
redis> incr c
QUEUED
redis> exec
1. (integer) 6
2. (error) ERR Operation against a key holding the wrong kind of value
3. (integer) 6

可以看到雖然incr b失敗了,但是其他兩個命令還是執行了。
最 後一個十分罕見的問題是 當事務的執行過程中,如果redis意外的掛了。很遺憾只有部分命令執行了,後面的也就被丟棄了。當然如果我們使用的append-only file方式持久化,redis會用單個write操作寫入整個事務內容。即是是這種方式還是有可能只部分寫入了事務到磁盤。發生部分寫入事務的情況 下,redis重啟時會檢測到這種情況,然後失敗退出。可以使用redis-check-aof工具進行修復,修復會刪除部分寫入的事務內容。修復完後就能夠重新啟動了。
Copyright © Linux教程網 All Rights Reserved