1. 程式人生 > 實用技巧 >Redis 事務機制

Redis 事務機制

Redis 事務:可以一次執行多個命令,本質是一組命令的集合。一個事務中的所有命令都會序列化,按順序序列化執行而不會被其它命令插入,一次性、順序性、排他性的執行一系列命令。

一、常用命令


【1】開啟一個事務
【2】 執行事務中的命令。可以看到 開始到 之間,所有的命令都會被加入到一個命令佇列中。當執行 命令後,將 QUEUED 中所有的命令執行。
【3】放棄事務

 1 127.0.0.1:6379> multi
 2 OK
 3 127.0.0.1:6379> set redis "redis"
 4 QUEUED
 5 127.0.0.1:6379> get redis
6 QUEUED 7 127.0.0.1:6379> sadd tag "java" "c" "c#" 8 QUEUED 9 127.0.0.1:6379> smembers tag 10 QUEUED 11 127.0.0.1:6379> exec 12 1) OK 13 2) "redis" 14 3) (integer) 3 15 4) 1) "c#" 16 2) "java" 17 3) "c" 18 19 #放棄執行案例 20 127.0.0.1:6379> multi 21 OK 22 127.0.0.1:6379> set mysql "mysql" 23
QUEUED 24 127.0.0.1:6379> get mysql 25 QUEUED 26 127.0.0.1:6379> discard 27 OK 28 127.0.0.1:6379> get mysql 29 (nil) 30 127.0.0.1:6379>

常見的兩種狀況:①、全體連坐(當語法有錯時,一條都不成功)②、冤頭債主(當時編譯時出錯,部分可以成功)

注意事項:Redis 的事務沒有提供類似於關係型資料庫的回滾(rollback),所以開發人員必須在事務執行失敗後進行後續的處理。

每個 Redis 客戶端都有自己的事務狀態,儲存在 multiState 屬性中,進一步,每一個事務狀態包含一個事務佇列以及已入隊命令的計數器,事務佇列是一個數組,陣列中的每個元素儲存了已入隊命令的相關資訊,包含指向命令實現函式的指標、命令的引數,以及引數的數量。

二、WATCH 監控


在 Nosql 資料庫中,CAS 是一種保證原子性的操作。Redis 也提供了這樣的一個機制,就是利用 Watch命令來實現的。Watch 指令,類似樂觀鎖(悲觀鎖:鎖整張表。樂觀鎖:鎖一行資料),事務提交時,如果 Key 的值已被別的客戶端改變,比如某個 list已被別的客戶端 push/pop 過了,整個事務佇列都不會被執行,通過 WATCH 命令在事務執行之前監控了多個 Keys,倘若在WATCH 之後有任何 Key 的值發生了變化,EXEC 命令執行的事務都將被放棄,同時返回 Nullmulti-bulk 應答以通知呼叫者事務執行失敗。

【1】客戶端1:對 key = redis 的值進行監控,並開啟事務後對 key = redis 的資料進行修改。如下:

1 127.0.0.1:6379> watch redis 
2 OK
3 127.0.0.1:6379> multi
4 OK
5 127.0.0.1:6379> set redis "redis"
6 QUEUED

【2】客戶端2:直接對 key = redis 的值進行修改。如下:

1 127.0.0.1:6379> set redis "re"
2 OK

【3】客戶端1:執行 EXEC 提交事務,會發現執行失敗。當獲取 redis 值時,發現是客戶2修改的值。

1 127.0.0.1:6379> exec
2 (nil)
3 127.0.0.1:6379> get redis
4 "re"

UNWATCH:取消監控,與 WATCH 命令相反。當指向提交事務EXEC 或取消事務DISCARD 時,會自動執行 UNWATCH 取消客戶端對某 key 的監控

三、小結


3 階段:【1】開啟:以MULTI開始一個事務
【2】入隊:將多個命令入隊到事務中,接到這些命令並不會立即執行,而是放到等待執行的事務佇列裡面
【3】執行:由EXEC命令觸發事務
3 特性:【1】單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷。
【2】沒有隔離級別的概念:佇列中的命令沒有提交之前都不會實際的被執行,因為事務提交前任何指令都不會被實際執行,也就不存在 ”事務內的查詢要看到事務裡的更新,在事務外查詢不能看到” 這個讓人萬分頭痛的問題。
【3】不保證原子性:redis 同一個事務中如果有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾。