Redis 事務簡介
稍微了解 Redis 的朋友都知道,Redis 也提供了事務功能,但是 Redis 的事務和我們平時熟悉的關系型資料庫中的事務是有區別的,

Redis 事務的本質是一組命令的集合:一個事務中所有命令都會被序列化到一個佇列中,在事務執行程序,會按照順序串行執行佇列中的命令,這些命令要么全部得到執行,要么全部不執行,另外,其他客戶端提交的命令請求不會插入到事務執行命令序列中,
Redis 事務的使用
Redis 事務的基礎是MULTI 、EXEC、DISCARD和WATCH等命令,
這些命令的使用方式如下:
# 開啟事務
MULTI
command1
command2
# 觸發事務
EXEC
MULTI 命令用于開啟一個事務,它總是回傳 OK ,MULTI執行之后, 客戶端可以繼續向服務器發送任意多條命令, 這些命令不會立即被執行, 而是被放到一個佇列中,
EXEC命令負責觸發并執行事務中的所有命令,EXEC命令的回復是一個陣列, 陣列中的每個元素都是執行事務中的命令所產生的回復, 其中, 回復元素的先后順序和命令發送的先后順序一致,
當使用 AOF 方式做持久化的時候, Redis 會令將事務寫入到磁盤中, 然而,如果 Redis 服務器因為某些原因被管理員殺死,或者遇上某種硬體故障,那么可能只有部分事務命令會被成功寫入到磁盤中,Redis 在重新啟動時發現 AOF 檔案出了這樣的問題,那么它會退出,并匯報一個錯誤, 使用 redis-check-aof 程式可以修復這一問題:它會移除 AOF 檔案中不完整事務的資訊,確保服務器可以順利啟動,
另外,需要注意的是:如果客戶端在使用 MULTI 開啟了一個事務之后,卻因為斷線而沒有成功執行 EXEC ,那么事務中的所有命令都不會被執行,
Redis 事務對錯誤的處理
使用事務時可能會遇上以下兩種錯誤:
- 事務在執行 EXEC 之前,入隊的命令可能會出錯,比如說,命令可能會產生語法錯誤(引數數量錯誤,引數名錯誤,等等),或者其他更嚴重的錯誤,比如記憶體不足(如果服務器使用
maxmemory設定了最大記憶體限制的話), - 命令可能在 EXEC 呼叫之后失敗,舉個例子,事務中的命令可能處理了錯誤型別的鍵,比如將串列命令用在了字串鍵上面,諸如此類,
對于在執行 EXEC 之前發生的錯誤,服務器會對命令入隊失敗的情況進行記錄,并在客戶端呼叫 EXEC 命令時,拒絕執行并自動放棄這個事務,
至于那些在 EXEC 命令執行之后所產生的錯誤, 并沒有對它們進行特別處理: 即使事務中有某個/某些命令在執行時產生了錯誤, 事務中的其他命令仍然會繼續執行,
對于第二種情況,敏感的朋友會問:Redis 發現錯誤時會不會回滾已經執行成功的操作呢?答案是不會,
Redis 給出的理由是:
- Redis 命令只會因為錯誤的語法而失敗(并且這些問題不能在入隊時發現),或是命令用在了錯誤型別的鍵上面:這也就是說,從實用性的角度來說,失敗的命令是由編程錯誤造成的,而這些錯誤應該在開發的程序中被發現,而不應該出現在生產環境中,
- 因為不需要對回滾進行支持,所以 Redis 的內部可以保持簡單且快速,
如果我們的程式中確實需要對事務進行回滾,可以結合使用 Lua 腳本來實作事務,簡單的做法是在事務開始前記錄狀態,如果在程式執行程序中發生了例外錯誤,將被修改的資料恢復到之前即可,
watch 命令的使用
WATCH 命令可以為 Redis 事務提供 check-and-set (CAS)行為,
被 WATCH 的鍵會被監視,并會發覺這些鍵是否被改動過了, 如果有至少一個被監視的鍵在 EXEC 執行之前被修改了, 那么整個事務都會被取消, EXEC 回傳空來表示事務已經失敗,
當發生被監控的鍵被改變時,程式需要做的就是不斷重試這個操作, 直到沒有發生碰撞為止,
下面我們來演示下 watch命令的使用:
127.0.0.1:6379> set csx:key:1 test
OK
127.0.0.1:6379> watch csx:key:1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> ping message1
QUEUED
127.0.0.1:6379> ping message2
QUEUED
# 在執行 exec 之前,使用另外一個客戶端將csx:key:1這個鍵的值修改了
127.0.0.1:6379> exec
(nil)
WATCH 使得 EXEC 命令需要有條件地執行: 事務只能在所有被監視鍵都沒有被修改的前提下執行, 如果這個前提不能滿足的話,事務就不會被執行,
如果你使用 WATCH 監視了一個帶過期時間的鍵, 那么即使這個鍵過期了, 事務仍然可以正常執行,
當 EXEC 被呼叫時, 不管事務是否成功執行, 對所有鍵的監視都會被取消,另外, 當客戶端斷開連接時, 該客戶端對鍵的監視也會被取消,
使用無引數的 UNWATCH 命令可以手動取消對所有鍵的監視, 對于一些需要改動多個鍵的事務, 有時候程式需要同時對多個鍵進行加鎖, 然后檢查這些鍵的當前值是否符合程式的要求, 當值達不到要求時, 就可以使用 UNWATCH 命令來取消目前對鍵的監視, 中途放棄這個事務, 并等待事務的下次嘗試,
一個問題
當 Redis 客戶端開啟了事務,并且也輸入了幾個命名,但是客戶端因為某些原因斷開了,那么 Redis 服務端是怎么處理那些已經進入佇列的命令的?
參考
- https://cloud.tencent.com/developer/article/1189074
- https://blog.csdn.net/weixin_45417821/article/details/107627359
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/166523.html
標籤:其他
上一篇:Redis 中的事務
