redis-事務

来源:https://www.cnblogs.com/shixiemayi/archive/2018/08/18/9496672.html
-Advertisement-
Play Games

事務 MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事務相關的命令。事務可以一次執行多個命令, 並且帶有以下兩個重要的保證: 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。 事務是一個原 ...


事務

MULTIEXECDISCARDWATCH 是 Redis 事務相關的命令。事務可以一次執行多個命令, 並且帶有以下兩個重要的保證:

  • 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。

  • 事務是一個原子操作:事務中的命令要麼全部被執行,要麼全部都不執行。

EXEC 命令負責觸發並執行事務中的所有命令:

  • 如果客戶端在使用 MULTI 開啟了一個事務之後,卻因為斷線而沒有成功執行 EXEC ,那麼事務中的所有命令都不會被執行。
  • 另一方面,如果客戶端成功在開啟事務之後執行 EXEC ,那麼事務中的所有命令都會被執行。

當使用 AOF 方式做持久化的時候, Redis 會使用單個 write(2) 命令將事務寫入到磁碟中。

然而,如果 Redis 伺服器因為某些原因被管理員殺死,或者遇上某種硬體故障,那麼可能只有部分事務命令會被成功寫入到磁碟中。

如果 Redis 在重新啟動時發現 AOF 文件出了這樣的問題,那麼它會退出,並彙報一個錯誤。

使用redis-check-aof程式可以修複這一問題:它會移除 AOF 文件中不完整事務的信息,確保伺服器可以順利啟動。

從 2.2 版本開始,Redis 還可以通過樂觀鎖(optimistic lock)實現 CAS (check-and-set)操作,具體信息請參考文檔的後半部分。

用法

MULTI 命令用於開啟一個事務,它總是返回 OKMULTI 執行之後, 客戶端可以繼續向伺服器發送任意多條命令, 這些命令不會立即被執行, 而是被放到一個隊列中, 當 EXEC命令被調用時, 所有隊列中的命令才會被執行。

另一方面, 通過調用 DISCARD , 客戶端可以清空事務隊列, 並放棄執行事務。

以下是一個事務例子, 它原子地增加了 foobar 兩個鍵的值:

> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1

EXEC 命令的回覆是一個數組, 數組中的每個元素都是執行事務中的命令所產生的回覆。 其中, 回覆元素的先後順序和命令發送的先後順序一致。

當客戶端處於事務狀態時, 所有傳入的命令都會返回一個內容為 QUEUED 的狀態回覆(status reply), 這些被入隊的命令將在 EXEC 命令被調用時執行。

事務中的錯誤

使用事務時可能會遇上以下兩種錯誤:

  • 事務在執行 EXEC 之前,入隊的命令可能會出錯。比如說,命令可能會產生語法錯誤(參數數量錯誤,參數名錯誤,等等),或者其他更嚴重的錯誤,比如記憶體不足(如果伺服器使用 maxmemory 設置了最大記憶體限制的話)。
  • 命令可能在 EXEC 調用之後失敗。舉個例子,事務中的命令可能處理了錯誤類型的鍵,比如將列表命令用在了字元串鍵上面,諸如此類。

對於發生在 EXEC 執行之前的錯誤,客戶端以前的做法是檢查命令入隊所得的返回值:如果命令入隊時返回 QUEUED ,那麼入隊成功;否則,就是入隊失敗。如果有命令在入隊時失敗,那麼大部分客戶端都會停止並取消這個事務。

不過,從 Redis 2.6.5 開始,伺服器會對命令入隊失敗的情況進行記錄,併在客戶端調用 EXEC 命令時,拒絕執行並自動放棄這個事務。

在 Redis 2.6.5 以前, Redis 只執行事務中那些入隊成功的命令,而忽略那些入隊失敗的命令。 而新的處理方式則使得在流水線(pipeline)中包含事務變得簡單,因為發送事務和讀取事務的回覆都只需要和伺服器進行一次通訊。

至於那些在 EXEC 命令執行之後所產生的錯誤, 並沒有對它們進行特別處理: 即使事務中有某個/某些命令在執行時產生了錯誤, 事務中的其他命令仍然會繼續執行。

從協議的角度來看這個問題,會更容易理解一些。 以下例子中, LPOP 命令的執行將出錯, 儘管調用它的語法是正確的:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
MULTI
+OK
SET a 3
abc
+QUEUED
LPOP a
+QUEUED
EXEC
*2
+OK
-ERR Operation against a key holding the wrong kind of value

EXEC 返回兩條bulk-string-reply: 第一條是 OK ,而第二條是 -ERR 。 至於怎樣用合適的方法來表示事務中的錯誤, 則是由客戶端自己決定的。

最重要的是記住這樣一條, 即使事務中有某條/某些命令執行失敗了, 事務隊列中的其他命令仍然會繼續執行 —— Redis 不會停止執行事務中的命令。

以下例子展示的是另一種情況, 當命令在入隊時產生錯誤, 錯誤會立即被返回給客戶端:

MULTI
+OK
INCR a b c
-ERR wrong number of arguments for 'incr' command

因為調用 INCR 命令的參數格式不正確, 所以這個 INCR 命令入隊失敗。

為什麼 Redis 不支持回滾(roll back)

如果你有使用關係式資料庫的經驗, 那麼 “Redis 在事務失敗時不進行回滾,而是繼續執行餘下的命令”這種做法可能會讓你覺得有點奇怪。

以下是這種做法的優點:

  • Redis 命令只會因為錯誤的語法而失敗(並且這些問題不能在入隊時發現),或是命令用在了錯誤類型的鍵上面:這也就是說,從實用性的角度來說,失敗的命令是由編程錯誤造成的,而這些錯誤應該在開發的過程中被髮現,而不應該出現在生產環境中。
  • 因為不需要對回滾進行支持,所以 Redis 的內部可以保持簡單且快速。

有種觀點認為 Redis 處理事務的做法會產生 bug , 然而需要註意的是, 在通常情況下, 回滾並不能解決編程錯誤帶來的問題。 舉個例子, 如果你本來想通過 INCR 命令將鍵的值加上 1 , 卻不小心加上了 2 , 又或者對錯誤類型的鍵執行了 INCR , 回滾是沒有辦法處理這些情況的。

放棄事務

當執行 DISCARD 命令時, 事務會被放棄, 事務隊列會被清空, 並且客戶端會從事務狀態中退出:

> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
"1"

使用 check-and-set 操作實現樂觀鎖

WATCH 命令可以為 Redis 事務提供 check-and-set (CAS)行為。

WATCH 的鍵會被監視,並會發覺這些鍵是否被改動過了。 如果有至少一個被監視的鍵在 EXEC 執行之前被修改了, 那麼整個事務都會被取消, EXEC 返回nil-reply來表示事務已經失敗。

舉個例子, 假設我們需要原子性地為某個值進行增 1 操作(假設 INCR 不存在)。

首先我們可能會這樣做:

val = GET mykey
val = val + 1
SET mykey $val

上面的這個實現在只有一個客戶端的時候可以執行得很好。 但是, 當多個客戶端同時對同一個鍵進行這樣的操作時, 就會產生競爭條件。舉個例子, 如果客戶端 A 和 B 都讀取了鍵原來的值, 比如 10 , 那麼兩個客戶端都會將鍵的值設為 11 , 但正確的結果應該是 12 才對。

有了 WATCH , 我們就可以輕鬆地解決這類問題了:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

使用上面的代碼, 如果在 WATCH 執行之後, EXEC 執行之前, 有其他客戶端修改了 mykey 的值, 那麼當前客戶端的事務就會失敗。 程式需要做的, 就是不斷重試這個操作, 直到沒有發生碰撞為止。

這種形式的鎖被稱作樂觀鎖, 它是一種非常強大的鎖機制。 並且因為大多數情況下, 不同的客戶端會訪問不同的鍵, 碰撞的情況一般都很少, 所以通常並不需要進行重試。

瞭解 WATCH

WATCH 使得 EXEC 命令需要有條件地執行: 事務只能在所有被監視鍵都沒有被修改的前提下執行, 如果這個前提不能滿足的話,事務就不會被執行。 瞭解更多->

WATCH 命令可以被調用多次。 對鍵的監視從 WATCH 執行之後開始生效, 直到調用 EXEC 為止。

用戶還可以在單個 WATCH 命令中監視任意多個鍵, 就像這樣:

redis> WATCH key1 key2 key3
OK

EXEC 被調用時, 不管事務是否成功執行, 對所有鍵的監視都會被取消。

另外, 當客戶端斷開連接時, 該客戶端對鍵的監視也會被取消。

使用無參數的 UNWATCH 命令可以手動取消對所有鍵的監視。 對於一些需要改動多個鍵的事務, 有時候程式需要同時對多個鍵進行加鎖, 然後檢查這些鍵的當前值是否符合程式的要求。 當值達不到要求時, 就可以使用 UNWATCH 命令來取消目前對鍵的監視, 中途放棄這個事務, 並等待事務的下次嘗試。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基本語法:select 查詢列表 from 表名 查詢列表可以是表中欄位、常量值、表達式、函數;查詢的結果是一個虛擬的表格。 註意: ①sql語言大小寫不敏感 ②關鍵字不能分行或略寫 ③一般書寫方式為換行縮進 一、基礎查詢 1.經典查詢(查詢表中的欄位) ①查詢單個欄位 select 欄位1 fro ...
  • DDL(Data Definition languages)數據定義語言,這些語句主要定義了不同的數據段,數據表、列、索引等操作,主要關鍵字有create、drop、alter。 一、 資料庫的操作 1.資料庫的創建 CREATE DATABASE IF NOT EXISTS chens; 2.數據 ...
  • 定義:數據操作語言主要實現對資料庫表中的數據進行操作,主要包括插入(insert)、更新(update)、刪除(delete)、查詢(select),本節主要介紹增刪改。 數據準備: 一、數據的插入(insert) 基本語法: insert into 表名(列名,...) values(值1,... ...
  • 1、Oracle win64_12g 安裝 1.下載安裝包:這裡需要自己註冊一下,然後就可以登錄下載軟體了。 下載地址: "http://www.oracle.com/technetwork/database/enterprise edition/downloads/index.html" 記得下載 ...
  • 1)安裝mysql ubuntu中安裝一臺mysql了,docker安裝另外一臺mysql 獲取mysql的鏡像,主從同步儘量保證多台mysql的版本相同,我的ubuntu中存在的mysql是5.7.22版本,所以獲取5.7.22版本的鏡像為例: 運行mysql docker鏡像,需要在宿主機中建立 ...
  • springboot作為現在十分流行的框架,簡化Spring應用的初始搭建以及開發過程,現在我們就使用springboot來進行簡單的web項目搭建並對項目sql進行監控。 項目的搭建就省略了,springboot項目搭建好以後,進行一下操作, 本例子的項目使用 maven 管理的jar 1.加入依 ...
  • 引發思考 今天,發現開發項目中的單號重覆了。 這是多用戶併發操作相同數據導致的結果。有點抽象,理解如下:實際就是多個事務交叉執行(增、刪、查、改)了相同數據。導致一個事務不具有完整性了,資料庫的數據也不一致了(這裡‘’一致‘’可以理解為:我希望的數據,跟我想像的不一樣,比如明明我剛update某表性 ...
  • 定義 函數用於計算和返回一個結果值,把經常需要進行的計算寫成函數,函數的調用是表達式的一部分。 函數與過程在創建的形式上有些相似,也是編譯後放在記憶體中供用戶使用。 函數必須有一個返回值,而過程沒有做強制的規定。 RETURN在聲明部分需要定義一個返回參數的類型,而在函數體中必須有一個RETURN語句 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...