徹底搞懂 Redis 事務


提到redis的事務,相信很多初學的朋友會對它的理解和使用有些模糊不清,料想它和我們常見的關系型數據庫(mysql 、mssql等)中的事務相同,也支持回滾,但這樣理解就進入了一個誤區,首先:關系型數據中的事務都是原子性的,而redis 的事務是非原子性的。再多說一句,什么是程序原子性?簡單的理解就是:整個程序中的所有操作,要么全部完成,要不全部不完成,不會停留在中間某個環節。那么非原子性就是不滿足原子性的條件就是非原子性了。我們用例子來解釋一下:

原子性:數據庫中的某個事務A中要更新t1表、t2表的某條記錄,當事務提交,t1、t2兩個表都被更新,若其中一個表操作失敗,事務將回滾。

非原子性:數據庫中的某個事務A中要更新t1表、t2表的某條記錄,當事務提交,t1、t2兩個表都被更新,若其中一個表操作失敗,另一個表操作繼續,事務不會回滾。(當然對於關系型數據庫不會出現非原子性)

Redis事務相關命令:

  • MULTI :開啟事務,redis會將后續的命令逐個放入隊列中,然后使用EXEC命令來原子化執行這個命令系列。
  • EXEC:執行事務中的所有操作命令。
  • DISCARD:取消事務,放棄執行事務塊中的所有命令。
  • WATCH:監視一個或多個key,如果事務在執行前,這個key(或多個key)被其他命令修改,則事務被中斷,不會執行事務中的任何命令。
  • UNWATCH:取消WATCH對所有key的監視。

下面具體看一下事務命令的使用:

1、MULTI開始一個事務:

(1) 給k1、k2分別賦值,在事務中修改k1、k2,執行事務后,查看k1、k2值都被修改。

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2 OK 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> EXEC 1) OK 2) OK 127.0.0.1:6379> get k1 "11" 127.0.0.1:6379> get k2 "22" 127.0.0.1:6379>

(2)事務失敗處理:

  •    語法錯誤(編譯器錯誤),在開啟事務后,修改k1值為11,k2值為22,但k2語法錯誤,最終導致事務提交失敗,k1、k2保留原值。
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2 OK 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> sets k2 22 (error) ERR unknown command `sets`, with args beginning with: `k2`, `22`, 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> 
  •    Redis類型錯誤(運行時錯誤),在開啟事務后,修改k1值為11,k2值為22,但將k2的類型作為List,在運行時檢測類型錯誤,最終導致事務提交失敗,此時事務並沒有回滾,而是跳過錯誤命令繼續執行, 結果k1值改變、k2保留原值。
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k1 v2 OK 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> lpush k2 22 QUEUED 127.0.0.1:6379> EXEC 1) OK 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 127.0.0.1:6379> get k1 "11" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379>

總結:為什么Redis不支持事務回滾?

以上兩個例子總結出,多數事務失敗是由語法錯誤或者數據結構類型錯誤導致的,語法錯誤說明在命令入隊前就進行檢測的,而類型錯誤是在執行時檢測的,Redis為提升性能而采用這種簡單的事務,這是不同於關系型數據庫的,特別要注意區分。

2、EXEC執行事務中的所有命令:

必須與MULTI命令成對使用

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 23 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> EXEC 1) OK 2) OK

 

3、DISCARD取消事務:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 33 QUEUED 127.0.0.1:6379> set k2 34 QUEUED 127.0.0.1:6379> DISCARD OK

4、WATCH監視key:

嚴格的說Redis的命令是原子性的,而事務是非原子性的,我們要讓Redis事務完全具有事務回滾的能力,需要借助於命令WATCH來實現。

Redis使用WATCH命令來決定事務是繼續執行還是回滾,那就需要在MULTI之前使用WATCH來監控某些鍵值對,然后使用MULTI命令來開啟事務,執行對數據結構操作的各種命令,此時這些命令入隊列。

當使用EXEC執行事務時,首先會比對WATCH所監控的鍵值對,如果沒發生改變,它會執行事務隊列中的命令,提交事務;如果發生變化,將不會執行事務中的任何命令,同時事務回滾。當然無論是否回滾,Redis都會取消執行事務前的WATCH命令。

 

 Redis執行事務過程

在事務開始前用WATCH監控k1,之后修改k1為11,說明事務開始前k1值被改變,MULTI開始事務,修改k1值為12,k2為22,執行EXEC,發回nil,說明事務回滾;查看下k1、k2的值都沒有被事務中的命令所改變。

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2 OK 127.0.0.1:6379> WATCH k1 OK 127.0.0.1:6379> set k1 11 OK 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 12 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> EXEC (nil) 127.0.0.1:6379> get k1 "11" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379>

5、UNWATCH取消監視所有key:

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2 OK 127.0.0.1:6379> WATCH k1 OK 127.0.0.1:6379> set k1 11 OK 127.0.0.1:6379> UNWATCH OK 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 12 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 127.0.0.1:6379> get k1 "12" 127.0.0.1:6379> get k2 "22" 127.0.0.1:6379>

 

參考資料:

http://c.biancheng.net/view/4544.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM