1. 程式人生 > >NoSQL之Redis高階實用命令詳解--事務處理

NoSQL之Redis高階實用命令詳解--事務處理

Redis事務處理

Redis對事務的支援目前還比較簡單。Redis只能保證一個client發起的事務中的命令可以連續執行,而中間不會插入其他client的命令。當一個client在一個連線中發出multi命令時,這個連線會進入一個事務上下文,該連線後續的命令不會立即執行,而是先放到一個佇列中,當執行exec命令時,redis會順序的執行佇列中的所有命令。

1.multi:開啟一個事務 exec執行一個事務

我們來看下面的例子:

127.0.0.1:6379> set money 100
OK

127.0.0.1:6379> get money
"100"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby money 150
QUEUED
127.0.0.1:6379> incrby money 150
QUEUED
127.0.0.1:6379> decrby money 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 250
2) (integer) 400
3) (integer) 300
127.0.0.1:6379> get money
"300"

首先我設定money為100,然後用multi開啟事務之後的操作就會被queued(放入佇列儲存),直到執行exec命令之後,佇列中的命令一起被執行,money被兩次+150然後-100最後結果是300.

注意:如果在multi和exec之間執行了一條錯誤命令,那麼exec執行也不會成功。

127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

2.discard:取消一個事務

127.0.0.1:6379> get money
"300"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set money 200
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
127.0.0.1:6379> get money
"300"

發現事務被取消之後再執行exec,就會告訴你沒有事務了。

money還是原來的300沒變。

3.redis事務的缺點

127.0.0.1:6379> set name 'test'
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr money
QUEUED
127.0.0.1:6379> incr name
QUEUED
127.0.0.1:6379> exec
1) (integer) 301
2) (error) ERR value is not an integer or out of range

發現事務並沒有回滾,而是把正確的執行了,而錯誤的沒有執行。

這個和第一種說的還不一樣,第一步中說的如果你在multi和exec中間執行了一條錯誤的命令(語法錯誤),那麼整個事務會失敗。而如果你沒有語法錯誤,那麼就不會回滾,也就失去了事務的真正意義,這是redis對事務處理有待改進的地方。

4.樂觀鎖複雜事務控制

樂觀鎖:大多數是基於資料版本(version)的記錄機制實現的。即為資料增加一個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料表新增一個“version”欄位來實現取出資料時,將此版本號一同讀出,之後更新時,對此版本號+1.此時,將提交資料的版本號與資料表對應記錄的當前版本號進行對比,如果提交的資料版本號大於資料庫當前版本號,則予以更新,否則認為是過期資料。-------svn 的版本控制就是最好的例子

Redis的樂觀鎖例項:假設有一個money的key,我們開2個session來對money進行賦值操作,我們來看一下結果如何?

Session1:

127.0.0.1:6379> get money
"301"
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby money 49
QUEUED

Session2:

127.0.0.1:6379> set money 400
OK
127.0.0.1:6379> get money
"400"

Session1:

127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get money
"400"

首先我們在session1中開啟了對money的監控(watch key開啟對key鍵的監控),然後開啟一個事務,把命令incrby money 49放到事務佇列中,等待exec執行處理。

之後我們開啟session2,在session2中我們直接set money 400,這個時候我們在session2中get一下money發現已經變成400

之後我們回到session1中再用exec去執行事務佇列中得incrby money 49這條命令,發現結果是nil也就是沒有成功,用get命令看一下money發現是400,而不是449.

整個過程就實現了一個樂觀鎖。

對watch的特別說明:

watch命令會監聽給定的key,當exec的時候如果監視的key從呼叫watch後發生過變化,則整個事務會失敗。也可以呼叫watch多次監聽多個key,這樣就可以對指定的key加樂觀鎖了。注意watch的key是對整個連線有效的,事務也一樣。如果連線斷開,監視和事務都會被自動清除。當然了exec,discard,unwatch命令都會清除連線中的所有監視。