Redis事務詳解,Redis事務不支持回滾嗎?

2020-12-11 架構師之路

Redis事務提供2個重要保證

MULTI, EXEC, DISCARD 和WATCH命令是Redis事務操作的基礎 。他們可以讓Redis在一個步驟裡執行一組命令,且能做到如下2個重要保證:

事務中的所有命令都是序列化且都是按順序執行的。在一個客戶端執行Redis事務的過程中,不會接收其他任何客戶端對它發出的請求。這保證了這些命令是作為一個單獨的獨立操作執行的。所有的命令要麼都被一起處理,要麼全都沒有被處理,所以Redis事務是原子的。EXEC會命令觸發事務中所有命令的執行。當正在使用AOF時,Redis會使用一個簡單的write(2)系統級調用來確保把事務寫入到磁碟。但是,如果Redis服務崩潰,或者被系統管理員以某種強制的方式殺死,那麼可能只有部分命令被寫入到磁碟。Redis在重新啟動時會檢測這種情況,並報錯,然後退出。使用 redis-check-aof工具可以檢查AOF,並移除那不完整的事務,使服務可以再次啟動

從 2.2 開始, Redis 可以用另外一個形式(樂觀鎖)來確保以上2點,後面講詳細討論.

用法

使用 MULTI 命令進入事務模式.這個命令只會返回OK。這個時候,用戶就可以發出多個要一起執行的命令了。 Redis暫時不會執行這些命令,而是把它們放進隊列。 當 EXEC 被調用時,所有的命令才會被一次性執行.

相反的,如果調用了 DISCARD 命令,則會清除事務隊列中的所有命令,然後退出事務.

下面一個示例,原子性的遞增keys foo 和 bar。

Redis使用事務原子性的遞增變量

從上面可以看出, EXEC 返回一個數組, 包含事務中每個命令的執行結果,且響應的順序和命令發出時的順序一樣。

當一個Redis連結正處於一個MULTI 請求的上下文時, 所有命令的響應結果都是字符串QUEUED。當調用EXEC時,會一次性執行這些命令。

錯誤

在Redis事物中,可能會發生2種錯誤:

命令可能排隊失敗。如,命令的語法可能是錯誤 (錯誤的參數個數,錯誤的命令名字 ...),或一些重要的環境問題,如,內存不足。當EXEC 調用 ,一些命令可能執行失敗,如,在一個字符串上進行了列表命令的操作。

第一種錯誤發生在 EXEC 命令之前,是很容易發現的,可以通過檢查命令的返回值:如果返回值是 QUEUED ,那麼它就是成功, 不然就是失敗,Redis會返回一個錯誤。如果在命令的隊列期間發出一個錯誤,通常的做法是,終止事務。

從 Redis 2.6.5 開始, 在命令排隊期間發生錯誤,Redis會拒絕執行 EXEC,並返回一個錯誤,然後自動放棄這個事務。

在 Redis 2.6.5 之前,EXEC調用後,會執行排隊成功的命令,忽略失敗的命令。

這新的規則讓事務和管道的一起使用變得簡單, 這樣整個事務都可以一起發送,然後一次性獲取所有的回覆,可以節省來往交互操作。

執行 EXEC :所有的命令都會被執行,甚至是那些錯誤的命令。

在下面的例子中,事務被執行,其中有一個命令返回失敗:

成功執行事務,但有一個命令錯誤

EXEC 返回2個字符串 ,其中一個是OK ,另一個是-ERR, 由客戶端來決定如何處理這個結果。

要注意的是 就算有命令失敗,隊列中的其他命令也會被執行。

當發生語法錯誤的時候,會儘快的報告錯誤:

語法錯誤會立即返回錯誤

以上是 INCR 命令的語法錯誤,它不會被放進命令隊列。

為什麼Redis不支持回滾

Redis命令在事務中可能會執行失敗,但是Redis事務不會回滾,而是繼續會執行餘下的命令。如果您有一個關係型資料庫的知識,這對您來說可能會感到奇怪,因為關係型數據在這種情況下都是會回滾的。

Redis這樣做,主要是因為:

只有當發生語法錯誤(這個問題在命令隊列時無法檢測到)了,Redis命令才會執行失敗, 或對keys賦予了一個類型錯誤的數據:這意味著這些都是程序性錯誤,這類錯誤在開發的過程中就能夠發現並解決掉,幾乎不會出現在生產環境。由於不需要回滾,這使得Redis內部更加簡單,而且運行速度更快。

放棄事務

DISCARD可以中止一個事務。這種情況下,不會執行任何命令,然後客戶端的連結的狀態會還原成正常狀態。

Redis放棄事務

樂觀鎖(check-and-set)

WATCH 命令為事務提供一個check-and-set (CAS) 行為。

WATCH 可以用來監聽事務中的隊列中的命令,在EXEC之前,一旦發現有一個命令被修改了的 , 那麼整個事務就會終止, EXEC返回一個 Null ,提示用戶事務失敗了。

例如, 我們要自動的遞增一個key (假設Redis還沒有實現 INCR命令).

那代碼可能如下:

如果在同一時間,只有一個客戶端在執行上面的操作,那麼上面的操作是可靠的。但如果同時有多個用戶執行上面的操作的話,那結果就是不可靠的了

我們可以使用 WATCH 來很好的解決這個問題:

使用以上的代碼,當有另一個用戶在我們調用WATCH 和 EXEC之間,修改了mykey的值val,那麼這個事務就會失敗。這種形式的鎖稱為樂觀鎖,是一種非常強大的鎖。

WATCH 說明

WATCH 到底是什麼意思呢? 這個命令使得 EXEC 命令的執行必須滿足一個條件:如果被WATCH的 keys 沒有一個被更改(但它們可以在事務中被修改),則執行事務;不然,就不會執行這個事務。(注意,如果你 WATCH了一個有生命周期的key,並且這個key過期了, EXEC 依然會執行)

WATCH 可以被多次調用。所有的WATCH 調用都會在 EXEC 調用之前起作用。WATCH可以接收任意多的key 。

當 EXEC 被調用後, 所有的keys都將UNWATCH,不管這個事務會不會終止。同樣,當一個客戶端連結關閉後, 一切都將UNWATCH。

可以使用UNWATCH (沒有參數)命令來刷新所有被WATCH的keys。有時會這樣操作,我們樂觀地鎖定了幾個keys,因為可能我們需要執行一個事務來修改這些keys,但是在讀取了keys的當前內容之後,我們不想繼續處理了。那麼這個時候,我們就可以調用UNWATCH。

用 WATCH 實現ZPOP

這是一個不錯的示例,它闡述了如何使用WATCH 來產生新的原子操作,這個沒有被Redis支持的ZPOP,這命令以原子的方式從一個有序集合中彈出較低的分數的值:

如果 EXEC 失敗 (如,返回 Null ) 我們只需要重新執行這個操作即可。

相關焦點

  • Redis事務其實是一個樂觀鎖機制
    總結特點:1.不支持回滾:沒有實現錯誤直接回滾的功能;2.不保證原子性:redis同一個事務中如果有一條命令執行失敗,其後的命令仍然會被執行,沒有自動支持回滾;3.隔離性:只保證了事務執行的隔離性為什麼不支持回滾呢?
  • 超強、超詳細Redis入門教程
    從小到大   withscores 帶上分數從大到小獲取商品 :  zrevrange  mobile:sales 0  10ZRANGEBYSCORE mobile:sales 97 100 limit 2 2  從第二條開始截取兩條應用場景: 商品的銷售排行榜Redis對事務的支持目前還比較簡單
  • Redis面試突擊專用
    Redis有部份存在硬碟上,redis可以持久化其數據 2)、數據支持類型 memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型 ,提供list,set,zset,hash等數據結構的存儲 3)、使用底層模型不同 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。
  • 總結一波 Redis 面試題
    Redis有部份存在硬碟上,redis可以持久化其數據2)、數據支持類型 memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型 ,提供list,set,zset,hash等數據結構的存儲3)、使用底層模型不同 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。
  • 總結一波 Redis 面試題,收藏起來.
    Redis有部份存在硬碟上,redis可以持久化其數據2)、數據支持類型 memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型 ,提供list,set,zset,hash等數據結構的存儲3)、使用底層模型不同 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。
  • 【187期】出現機率比較大的Redis面試題(含答案)
    Redis有部份存在硬碟上,redis可以持久化其數據2)、數據支持類型 memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型 ,提供list,set,zset,hash等數據結構的存儲3)、使用底層模型不同 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣
  • Hunt Redis 1.0.0 發布,D 語言 Redis 客戶端
    基礎特性: 排序 連結管理 不同類型的value的命令處理 String類型的命令處理 Hashes類型的命令處理 Lists類型的命令處理 Sets類型的命令處理 Sorted Sets類型的命令處理 事務
  • Redis的各項功能解決了哪些問題
    同時支持strings,lists,hashes,sets,sorted sets,bitmaps,hyperloglogs和geospatial indexes等數據類型。它還內建了複製,lua腳本,LRU,事務等功能,通過redis sentinel實現高可用,通過redis cluster實現了自動分片。以及事務,發布/訂閱,自動故障轉移等等。
  • Redis詳解:sets數據類型及操作
    系列文章:  Redis詳解:strings數據類型及操作  Redis詳解:hashes數據類型及操作  Redis詳解:lists數據類型及操作  Redis的set是string類型的無序集合。set元素最大可以包含(2的32次方)個元素。
  • 三歪推薦:Redis常見的面試題
    知道什麼是熱key嗎?熱key問題怎麼解決?所謂熱key問題就是,突然有幾十萬的請求去訪問redis上的某個特定key,那麼這樣會造成流量過於集中,達到物理網卡上限,從而導致這臺redis的伺服器宕機引發雪崩。
  • 5分鐘完全掌握 Redis
    知道什麼是熱key嗎?熱key問題怎麼解決?所謂熱key問題就是,突然有幾十萬的請求去訪問redis上的某個特定key,那麼這樣會造成流量過於集中,達到物理網卡上限,從而導致這臺redis的伺服器宕機引發雪崩。
  • 46道Redis面試題,含參考答案!
    1.memcached 所有的值均是簡單的字符串,redis 作為其替代者,支持更為豐富的數據類型2.redis 的速度比 memcached 快很多 redis 的速度比 memcached 快很多3.redis 可以持久化其數據 redis 可以持久化其數據3、Redis 支持哪幾種數據類型?
  • 一不小心肝出了4W字的Redis面試教程
    redis事務前言前幾天有讀者說自己面試被問到Redis的事務,雖然不常用,但是面試竟然被問到,平時自己沒有注意Redis的事務這一塊,面試的時候被問到非常不好受。雖然,這位讀者面試最後算是過了,但是薪資方面沒有拿到自己理想的薪資。
  • Python | Python學習之Redis交互詳解
    nosql與redis介紹nosql資料庫:不支持SQL語法存儲結構跟傳統關係型資料庫中的那種關係表完全不同,nosql中存儲的數據都是KV形式NoSQL的世界中沒有一種通用的語言,每種nosql資料庫都有自己的api和語法,以及擅長的業務場景NoSQL中的產品種類相當多:Mongodb,Redis,Hbase hadoop,Cassandra
  • acl 框架中的 Redis 庫已經支持集群版 Redis 3.0
    據 redis 官方網站顯示,支持集群版的 redis3.0 快要發布了(現在已經到了redis3.0 rc4 版本),這樣使用者就不需要自己花很大力氣來針對
  • 最全總結 | 聊聊 Python 數據處理全家桶(Redis篇)
    =True,如果不加則寫入的為字節類型        # host:遠程連接地址        # port:Redis埠號        # password:Redis授權密碼        self.redis_obj = Redis(host='139.199.**.
  • 史上最全 50 道 Redis 面試題
    (1) memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型(2) redis的速度比memcached快很多(3) redis可以持久化其數據3、Redis支持哪幾種數據類型?String、List、Set、Sorted Set、hashes4、Redis主要消耗什麼物理資源?內存。
  • Spring Data Redis使用
    本文是Redis系列的第十四篇文章,了解前面的文章有助於更好的理解本文:1.Linux上安裝Redis2.Redis中的五種數據類型簡介3.Redis字符串(STRING)介紹4.Redis字符串(STRING)中BIT相關命令5.Redis列表與集合6.Redis散列與有序集合7.Redis中的發布訂閱和事務8.Redis
  • 從一筆金幣充值去思考分布式事務,五種方案詳解!
    這個時候就需要進行流程恢復JobController 任務控制器定時去 redis 查詢延時任務列表(每個任務都有一個時間戳,按時間戳排序過濾)將任務進行恢復(調用 job 註冊時定義的處理方法)任務執行成功,表示流程完成;否則下一個定時周期重試問題:基於 redis 存儲恢復任務,可能存在數據丟失風險架構體系中沒有統一的分布式事務規範
  • Spring的編程式事務和聲明式事務詳解
    註解的方式),便可以將事務規則應用到業務邏輯中;非侵入式的開發方式,聲明式事務管理使業務代碼不受汙染,一個普通的POJO對象,只要加上註解就可以獲得完全的事務支持;是侵入性事務管理,直接使用底層的PlatformTransactionManager、使用TransactionTemplate(Spring推薦使用);編程式事務管理對基於 POJO 的應用來說是唯一選擇。