redis 淺談事務
寫在前面的話
之前在某個網站上看到一個問題:redis在什麼情況下出現事務不會滾的情況,以此為由並結合redis官方文檔整理這邊筆記。不足之處,請指出,謝謝。
事務
redis支援事務,提供兩條重要的保證:
- 在同一個事務的命令都是序列化的和有序執行的。這保證這些命令執行像單個隔離操作。
- 要麼所有的命令都執行,要麼都不執行。所以事務也是原子性的。exec命令執行事務中的所有命令,如果在調用exce命令前,客戶端和服務端斷開連接,那麼沒有一個命令執行,如果exce命令調用,所有的命令執行。當使用aof時,redis確保使用一個系統調用write(2)將事務寫到磁碟。然而如果redis服務崩潰或者系統管理員強制殺死,就會有可能只有一部分操作被註冊。redis在重啟時會發現這種情況,並且錯誤退出。使用redis-check-aof工具修復aof文件,移除部分事務,因為服務可以重啟。
事務內部錯誤
在事務期間可能會出現兩種命令錯誤:
- 命令可能失敗排隊,因此在exec調用之前,就會出現錯誤。如命令的語法錯誤(參數個數錯誤,命令名錯誤),或者其他災難環境如oom。
- 命令失敗可能在exec調用之後,例如操作一個key使用錯誤的值(如調用list操作卻調用string的命令)。
客戶端知道第一種錯誤,在執行exec之前,通過檢測返回值:如果是queued 表明正確的排隊,否則返回失敗資訊。如果在期間出現異常,大多數客戶端取消執行事務。
為什麼redis不支援回滾
如果你了解資料庫,就應該知道事務回滾,事實上redis命令在事務期間失敗,仍然執行剩餘的操作,而不是回滾,對於你來說,可能太古怪。
- redis命令只有調用錯誤語法才可能失敗(在命令隊列隊列中可能發現不了),或者操作key使用錯誤的數據類型:這意味著實際這種命令會導致程式錯誤,並且這種錯誤應該在開發環境發現,而不是生產。
- redis內部實現簡單和快速的,因為它不需要支援事務回滾。
事務操作命令
multi //開啟事務 exec // 執行事務 discard //取消事務塊執行 watch unwatch
事務執行事務回滾失敗
127.0.0.1:6379> multi OK 127.0.0.1:6379> set key1 value1 QUEUED //語法校驗通過。 127.0.0.1:6379> set key2 value2 QUEUED 127.0.0.1:6379> incr key1 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) (error) ERR value is not an integer or out of range 127.0.0.1:6379> get key1 "value1" 127.0.0.1:6379> get key2 "value2"
事務執行完成,但是沒有因為錯誤而失敗,這種失敗是Key對應的數據類型錯誤,屬於開發階段的錯誤,redis檢測不出來這種錯誤,只有實際執行才能校測出問題。
127.0.0.1:6379> multi OK 127.0.0.1:6379> set key1 value1 QUEUED 127.0.0.1:6379> set key2 value2 QUEUED 127.0.0.1:6379> incre key1 (error) ERR unknown command `incre`, with args beginning with: `key1`, 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get key1 (nil)
這種錯誤屬於語法錯誤,沒有incre命令,redis能檢測出這種錯誤,所以事務執行失敗。
取消事務
127.0.0.1:6379> multi OK 127.0.0.1:6379> set key1 value1 QUEUED 127.0.0.1:6379> discard OK 127.0.0.1:6379> get key1 (nil) 127.0.0.1:6379>