47 redis事務之理論簡介
什么是事務
可以一次執行多個命令,本質是一組命令的集合。一個事務中的所有命令都會序列化,按順序地串行化執行而不會被其它命令插入
能干什么?
一個隊列中,一次性、順序性、排他性的執行一系列操作
redis事務vs數據庫事務
1 單獨的隔離操作
????????Redis的事務僅僅是保證事務里的操作會被連續獨占的執行,redis命令執行是單線程架構,在執行完事務內所有指令前是不可能再去同時執行其他客戶端的請求的
2 沒有隔離級別的概念
????????因為事務提交前任何指令都不會被實際執行【只是放在隊列里面不會執行】,也就不存在“事務內的查詢要看到事務里的更新,在事務外查詢不能看到”這種問題了
3不保證原子性
????????Redis的事務不保證原子性,也就是不保證所有指令同時成功或同時失敗,只有決定是否開始執行全部指令的能力,沒有執行到一半進行回滾的能力
4 排它性
????????Redis會保證一個事務內的命令依次執行,而不會被其它命令插入
48 redis事務之案例實操
Redis 事務是通過 MULTI
命令進入的。該命令始終返回 OK
。此時,用戶可以發送多個命令,但 Redis 不會立即執行這些命令,而是將它們排入隊列中。所有命令會在調用 EXEC
命令后一次性執行。
如果調用 DISCARD
命令,則會清空事務隊列并退出事務
redis事務命令
1.DISCARD? ? ? ? 取消事務→放棄執行事務塊內的所有命令。
2.EXEC????????執行所有事務塊內的參令。
3.MULTI????????標記一個事務塊的開始。
4.UNWATCH????????取消WATCH 命令對所有key的監視,
5.WATCH key [key .. ]????????監視一個(或多個)key,如果在事勞執行之前這個(或這些)key被其他命令所改動,那么事務將被打斷。
CASE1:正常執行
MULTI 和?EXEC
CASE2:放棄事務
MULTI 和?DISCARD
CASE3:全體連坐
一條命令出錯,就全部放棄執行
127.0. 0.1:6379> MULTI
OK
127. 0. 0. 1: 6379(TX)> set k1 v111
QUEUED
127.0. 0. 1: 6379( TX)> set k2 v222
QUEUED
127.0.0.1:6379(TX)> set k3? ?// 這個命令本身就是錯誤的
(error) ERR wrong number of arguments for 'set' command
127. 0. 0. 1: 6379( TX) >
127. 0. 0. 1: 6379( TX) > EXEC
EXECABORT Transaction discarded because of previous errors.? //事務隊列中的所有命令都不執行
事務中的錯誤
在事務過程中,可能會遇到兩類命令錯誤:
-
命令在排隊階段失敗:也就是說,在調用
EXEC
之前就發生了錯誤。例如,命令可能存在語法錯誤(參數數量錯誤、命令名稱錯誤等),或者遇到某些關鍵問題,如內存不足(例如服務器配置了maxmemory
指令設置了內存上限)。-
這種情況只能全部命令都放棄執行
-
-
命令在
EXEC
后執行時失敗:例如,對某個鍵執行了不適用的操作(比如對一個字符串類型的鍵執行列表操作)。
CASE4:冤頭債主
在執行 EXEC
之后發生的錯誤不會被特殊處理:即使事務中的某個命令執行失敗,其他命令仍然會被繼續執行。
總結:對的放行,錯的不執行
補充:redis不提供事務回滾的功能,開發者必須在事務執行出錯后,自行恢復數據庫狀態。
INCR email命令錯誤:郵箱是字符串不可能自增
CASE5:watch監控
redis的watch類似于樂觀鎖的設定,類似于CAS
悲觀鎖是一種假設“總會發生沖突”的鎖機制。假設每次訪問數據都是對數據進行修改。因此在對數據進行操作前,會先加鎖,防止其他線程同時訪問,以確保數據安全。
樂觀鎖假設“并發沖突是少數”,所以不加鎖。 假設每次訪問數據都不會修改數據。因此在更新數據時才校驗數據是否被其他線程修改。
CAS 是一種無鎖的原子操作,全稱是 比較并交換。它是樂觀鎖的具體實現方式之一,底層依賴于 CPU 的原子指令。
工作原理:
-
先讀取變量的舊值
-
和預期值進行比較
-
如果相等,則更新為新值
-
如果不等,說明有其他線程修改過,則重試或失敗
watch
初始化k1和balance兩個key,先監控再開啟multi,保證兩key變動在同一個事務內
127. 0. 0. 1:6379> set k1 abc
OK
127. 0. 0. 1: 6379> set balance 100
OK
127. 0. 0. 1:6379>
127. 0. 0. 1: 6379> WATCH balance
OK
127.0. 0.1:6379>
127. 0. 0. 1: 6379> MULTI
OK
127. 0. 0. 1: 6379( TX) > set k1 abc2
QUEUED
127. 0. 0. 1: 6379( TX) > set balance 110
QUEUED
127. 0. 0. 1: 6379( TX) > EXEC
1) OK
2) OK
127.0. 0. 1:6379> get k1
"abc2"
有加塞篡改:
????????客戶端1監控了balance
????????客戶端2修改了balance
????????客戶端1的事務執行失敗返回空
unwatch
UNWATCH
用于 取消之前通過 WATCH
命令監視的所有鍵,避免這些鍵的變動影響事務的執行。
-
在你使用
WATCH
命令監控某些鍵的變化時,如果你不再想基于這些鍵判斷是否執行事務,就可以用UNWATCH
來取消。 -
如果你調用了
DISCARD
,Redis 會自動UNWATCH
,無需手動取消。
WATCH mykey
GET mykey
UNWATCH ? ? ? # 取消監視
MULTI
SET mykey "newvalue"
EXEC
小結
一旦執行了exec之前加的監控鎖都會被去掉。
當客戶端連接丟失【比如退出連接】,所有東西都會被取消監視