Redis中的事务
Redis中的事務
參考
參考博客:https://blog.csdn.net/jiayi_yao/article/details/124689937
菜鳥教程:https://www.runoob.com/redis/redis-transactions.html
參考博客:https://blog.csdn.net/weixin_46156200/article/details/121043694?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-121043694-blog-124689937.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-121043694-blog-124689937.pc_relevant_aa&utm_relevant_index=1
參考書籍:《Redis設計與實現》
Redis事務基本概念
Redis的事務是什么?
Redis事務是指將多條命令加入隊列,一次批量執行多條命令,每條命令會按順序執行,事務執行過程中不會受客戶端傳入的命令請求影響。
一個事務從開始到執行會經歷以下三個階段:
EXEC:創建回復隊列,依次遍歷事務隊列,取得結果放入回復隊列,執行完畢后,清空事務隊列,修改Redis客戶端狀態為非事務狀態(非事務狀態,接到命令就會立即執行),然后將回復隊列返回給前端
Redis事務的相關命令如下:
MULTI:標識一個事務的開啟,即開啟事務;
EXEC:執行事務中的所有命令,即提交;
DISCARD:放棄事務;和回滾不一樣,Redis事務不支持回滾。
WATCH:監視Key改變,用于實現樂觀鎖。如果監視的Key的值改變,事務最終會執行失敗。
UNWATCH:放棄監視。
使用WATCH實現樂觀鎖
說到樂觀鎖,就和悲觀鎖一起簡單說說對其的理解:
樂觀鎖:就是非常樂觀,做什么事都往好處想; 對于數據庫操作,就認為每次操作數據的時候都認為別的操作不會修改,所以不會加鎖,而是通過一個類似于版本的字段來標識該數據是否修改過,在執行本次操作前先判斷是否修改過,如果修改過就放棄本次操作重新再來。樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量;樂觀鎖策略:提交版本必須大于記錄當前版本才能執行更新。
悲觀鎖:就是非常悲觀,做什么事都覺得不好;對于數據庫操作,每次操作數據數據都會認為別的操作會修改當前數據,所以都要對其進行加鎖,類似于表鎖和行鎖。
WATCH通過監視指定Redis Key,如果沒有改變,就執行成功,如果發現對應值發生改變,事務就會執行失敗。
(WATCH命令一般在開啟事務之前使用)
那會一直監視指定的Key嗎?,答案是不會的,以下三種方式可以取消監視:
- 事務執行之后,不管是否執行成功還好是失敗,都會取消對應的監視;
- 當監視的客戶端斷開連接時,也會取消監視;
- 可以手動UNWATCH取
- 消所有Key的監視;
WATCH如何實現?
每個Redis數據庫都保存著一個watched_keys字典,這個字典的鍵是某個被WATCH命令監視的數據庫鍵,字典的值是一個鏈表,鏈表中記錄了所有監視相應數據庫鍵的客戶端。
通過watched_keys字典,服務器可以清楚地知道,那些數據庫鍵正在被監視,以及那些客戶端在監視。
監視機制的觸發
所有對數據庫修改的命令,例如SET、LPUSH、SADD等,在執行之后都會調用multi.c/touchWatchKey函數對watched_keys字典進行檢查,查看是否有客戶端正在監視剛剛修改的數據庫鍵,如果有,那么touchWatchKey函數會將監視被修改的客戶端的REDIS_DIRTY_CAS表示打開,表示該客戶端的數據安全性已經被破壞。
判斷事務是否安全
當客戶端接收到一個客戶端發來的EXEC命令時,服務器會根據這個客戶端是否打開了REDIS_DIRTY_CAS來決定是否會執行該事務:
- 如果客戶端的REDIS_DIRTY_CAS表示已經被打開,那么說明這個客戶端監視的鍵中,至少有一個已經被修改了,這種情況下,客戶端提交的事務已經不安全了,所以服務器會拒絕執行客戶端提交的事務
- 如果客戶端的REDIS_DIRTY_CAS表示沒有被打開,說明客戶端監視的所有的鍵都沒有被修改(或者這個事務沒有監視任何鍵),事務仍然是安全的,服務器將執行客戶端提交的這個事務
事務的ACID性質
在Redis中,事務總是具有原子性,一致性,隔離性,在某些特定的持久化模式下,事務也具有持久性。
原子性
事務具有原子性是指得是,數據庫事務中的一個操作會當作一個整體來執行,服務器要么所有操作都執行,要么都不執行。
對于Redis事務來說,事務中的命令要么全部執行,要么全不執行,因此Redis事務是具有一定的原子性的。Redis事務和傳統事務最大的區別是,Redis不支持事務回滾機制,即使事務隊列中有一個操作執行中發生錯誤,整個事務還會繼續執行,直到所有事務執行完畢,并且之前執行的命令也不會受到影響。
Redis事務中沒有提供回滾的支持,官方提供了理由:
不支持事務回滾是因為這種復雜的功能和Redis追求的簡單高效不相符,他認為Redis事務執行錯誤,通常都是編程錯誤產生的,這種錯誤通常只會出現在開發環境,而很少會出現在實際的生產環境,沒有必要增加回滾功能。
一致性
事務具有一致性指的是,如果數據庫在執行事務前是一致的,那么執行事務后,無論成功與否,也應該是一致的。“一致”指的是數據符合數據庫本身的定義和要求,沒有包含非法或者無效的錯誤數據。
Redis通過謹慎的錯誤檢測和簡單的設計來保證事務的一致性。之后將介紹幾個事務可能出錯的地方,來說明Redis如何保證事務的一致性。
入隊錯誤
如果一個事務在入隊命令的時候,出現了命令不存在或者命令格式不存在等請況,那么Redis將拒絕執行這個事務。因為服務器拒絕執行入隊過程中出現錯誤的事務,所以Redis事務一致性不會被有入隊錯誤的事務影響。
執行錯誤
執行時錯誤,就是那種無法在入隊時被服務器發現的錯誤,這些問題只會實際使用的時候觸發。即使事務在執行的過程中發生了錯誤,服務器也不會中斷事務地執行,它會繼續執行剩下的命令,并且已執行的命令不會被出錯的命令影響。
因為在事務的執行過程中,出錯的命令會被服務器識別出來,并進行相應的錯誤處理,所以這些出錯的命令不會對數據庫做任何修改,也不會對事務的一致性產生影響。
服務器宕機
如果Redis執行過程中宕機,根據服務器使用的持久化模式,可能出現以下情況:
- 如果服務器運行在無持久化的內存模式下,那么重啟之后的數據庫是空白的,因此數據總是一致
- 如果服務運行在RDB模式下,那么事務中途停機不會導致不一致性,因為服務器可以根據現有的RDB文件來恢復數據,并且事務執行過程中不會進行RDB,所以恢復后的數據庫能到達一個一致的狀態。如果找不到可用的RDB文件,那么數據庫就是空白的,空白的數據庫總是一致的。
- 如果服務器運行在AOF模式下,那么在事務中途不會導致不一致性,因為服務器可以根據AOF文件來恢復數據,從而將數據庫庫恢復到一個一致的狀態,如果有部分數據寫入到了AOF,我們可以通過redis-check-aof清除已完成的一些操作,來保證一致性。
綜上,服務器無論在哪種持久化方式下,事務中途停止都不會影響一致性。
隔離性
事務的隔離性指的是,即使數據庫中有多個事務并發地執行,各個事務之間也不會相互影響,并且在并發狀態下執行的事務和串行下的結果完全相同。
因為Redis是單線程來執行,并且服務器抱枕,執行事務期間,不會對事務進行中斷,因此Redis事務總是以串行的方式運行,并且事務也總是具有隔離性。
持久性
事物的持久性是指,當事務執行完畢,執行這個事務所得的結果都保存到非易失存儲器上,即使服務器停機,執行事務得到的結果也不會丟失。
因為Redis事務至少用隊列包裹了一組Redis命令,Redis并沒有為事務提供持久化功能,所以Redis事務的持久性就由Redis采用的持久化方式決定:
- 服務器無任何持久化方式,事務不具有持久性,服務器停機,數據消失
- 當服務器采用RDB持久方式時,服務器只會在特定的保存條件被滿足時,執行BGSAVE命令,對數據庫進行保存操作,異步執行的BGSAVE不能保證事務的結果第一時間寫入到硬盤,所以不具備持久性
- 采用AOF方式,且appendsync=always,每次執行命令,就調用同步函數存入硬盤,所以具有持久性
- 采用AOF方式,且appendsync=everysync,程序一秒同步一次,所以可能會導致修改丟失,所以不具有持久性
- 采用AOF方式,且appendsync=no,交給服務器來判斷同步時機,所以可能會導致修改丟失,所以不具有持久性
Redis事務優缺點
優點:
一次性按順序執行多個Redis命令,不受其他客戶端命令請求影響;
事務中的命令要么都執行(命令間執行失敗互相不影響),要么都不執行(比如中間有命令語法錯誤);
缺點:
事務執行時,不能保證原子性;
命令入隊每次都需要和服務器進行交互,增加帶寬(可以使用LUA腳本,一次發送所有的命令,減少帶寬);
注意:
當事務中命令語法使用錯誤時,最終會導致事務執行不成功,即事務內所有命令都不執行;
當事務中命令知識邏輯錯誤,就比如給字符串做加減乘除操作時,只能在執行過程中發現錯誤,這種事務執行中失敗的命令不影響其他命令的執行。
Redis事務應用場景
Redis事務因為特性的原因,沒有什么應用場景,如果大家有了解的應用場景,歡迎補充。
總結
- 上一篇: linux0.11文件分析
- 下一篇: PHPmysqli的 预处理执行查询语句