Redis(3)---Redis事務
Redis事務
Redis 通過 MULTI 、EXEC、 DISCARD 和 WATCH 四個命令來實現事務功能。
MULTI :標記一個事務塊的開始。
EXEC: 執行所有事務塊內的命令。
DISCARD :取消事務,放棄執行事務塊內的所有命令。
WATCH key [key ...] :監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麽事務將被打斷。
一、事務
1、是什麽?
可以一次執行多個命令,本質是一組命令的集合。一個事務中的所有命令都會序列化,不許加塞!
2、能幹什麽?
一個隊列中,一次性的、順序性的、排他性的執行一系列的命令。要麽一起成功,要麽一起失敗。排好隊,一次性的執行多個redis的命令!
3、怎麽玩?
通過MULTI指令開啟,之後輸入多個命令!Redis將它們加入到隊列當中,所有的命令通過EXEC來開啟執行!通過DISCARD來放棄本次的批處理操作!
(1)正常執行(好比購物先加入購物車,最後EXEC統一結賬。)
192.168.1.66:6379> MULTI --開啟事務 OK 192.168.1.66:6379> set k1 v1 QUEUED 192.168.1.66:6379> set k2 v2 QUEUED 192.168.1.66:6379> set k3 v3 QUEUED 192.168.1.66:6379> set k4 v4 QUEUED 192.168.1.66:6379> get k2 QUEUED 192.168.1.66:6379> EXEC --結束事務 1) OK 2) OK 3) OK 4) OK 5) "v2"
(2)DISCARD 撤銷所有操作!
192.168.1.66:6379> MULTI OK 192.168.1.66:6379> setk1 11 QUEUED 192.168.1.66:6379> set k2 22 QUEUED 192.168.1.66:6379> set k3 33 QUEUED 192.168.1.66:6379> DISCARD OK 192.168.1.66:6379> get k1 --這裏的k1的value值還是上面的值,而不是新設置的value值 "v1"
(3)加入隊列時不出錯,下面的都將正常運行,執行時出錯不影響其他語句!
192.168.1.66:6379> set k1 v1 OK 192.168.1.66:6379> set k2 v2 OK 192.168.1.66:6379> MULTI OK 192.168.1.66:6379> incr k1 QUEUED 192.168.1.66:6379> set k2 22 QUEUED 192.168.1.66:6379> EXEC 1) (error) ERR value is not an integer or out of range --在運行是才發現k1不是數字,報錯 2) OK --執行成功
註意:
(1)當遇到執行錯誤時,redis放過這種錯誤,保證事務執行完成。(所以說redis的事務並不是保證原子性)
(2)與mysql中事務不同,在redis事務遇到執行錯誤的時候,不會進行回滾,而是簡單的放過了,並保證其他的命令正常執行。這個區別在實現業務的時候,需要自己保證邏輯符合預期。
(3)當事務的執行過程中,如果redis意外的掛了。很遺憾只有部分命令執行了,後面的也就被丟棄了。當然如果我們使用的append-only file方式持久化,redis會用單個write操作寫入整個事務內容。即是是這種方式還是有可能只部分寫入了事務到磁盤。發生部分寫入事務的情況 下,redis重啟時會檢測到這種情況,然後失敗退出。可以使用redis-check-aof工具進行修復,修復會刪除部分寫入的事務內容。修復完後就 能夠重新啟動了。
二、WATCH
WATCH 命令可以為 Redis 事務提供 check-and-set (CAS)行為。
被 WATCH 的鍵會被監視,並會發覺這些鍵是否被改動過了。 如果有至少一個被監視的鍵在 EXEC 執行之前被修改了, 那麽整個事務都會被取消, EXEC 返回空多條批量回復(null multi-bulk reply)來表示事務已經失敗。
1、首先我們不加WATCH進行事務處理
時間 |
客戶端 A |
客戶端 B |
說明 |
T1 |
SET name aa SET age 10 |
GET name aa GET age 10 |
數據庫中兩客戶端登錄,及鍵初始值。 它們是同步的。 |
T2 |
MULTI SET name bb Incr age |
此時,客戶端1開啟事務,並提交隊列命令: 1.想要將當前age自增+1運算; 2.將name值改為bb |
|
T3 |
SET name cc Incr age |
此時,客戶端2修改了age值 同時修改name值為cc |
|
T4 |
EXEC |
|
|
T5 |
GET name bb GET age 12 |
此時,客戶端1執行隊列命令,發現運算之後age不是理想中的11,而是12原因是被其它客戶插足搶先給修改了。name值確實是沒有被其它所改變。這樣可能導致數據不一致性。 |
2、添加WARCH
客戶端1-引入“樂觀鎖”機制 | 客戶端2 | 說明 |
SET age "10" SET name "zhangsan" |
GET age "10" GET name "zhangsan" |
數據庫中兩客戶端登錄,及鍵初始值。 |
WATCH age name OK MUTLI OK incr age QUEUED set name lisi QUEUED |
此時,客戶端1用watch命令監視age和name,然後開啟事務,並提交隊列命令 | |
incr age (integer) 11 |
此時,客戶端2修改了age值 | |
exec (nil) get age "11" get name "zhangsan" |
此時,客戶端1執行隊列命令,由watch監控發現此期間age的值已經被修改過,則讓事整個務回滾,不做任何動作。 watch可以同時監控多個鍵,在監控期間只要有一個鍵被其它客戶端改變,則整個事務回滾。 |
想太多,做太少,中間的落差就是煩惱。想沒有煩惱,要麽別想,要麽多做。少校【1】
Redis(3)---Redis事務