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>