Redis 6. redis的事務
阿新 • • 發佈:2019-01-05
Redis
@Author:hanguixian
@Email:[email protected]
六 事務
1 是什麼
- 中文官網: http://www.redis.cn/topics/transactions.html
- 官網: https://redis.io/topics/transactions
- 可以一次執行多個命令,本質是一組命令的集合。一個事務中的所有命令都會序列化,按順序地序列化執行而不會被其它命令插入,不許加塞
2 能幹嘛
- 一個佇列中,一次性、順序性、排他性的執行一系列命令
3 使用
3.1 常用命令
- DISCARD:取消事務,放棄執行事務塊內的所有命令
- EXEC:執行所有事務塊內的命令
- MULTI:標記一個事務塊的開始
- UNWATCH:取消WATCH命令對所有key的監視
- WATCH:監視一個(多個)key,如果事務執行之前這個(或這些)key被其他命令索改動,那麼事務將被打斷
3.2 執行的五種情況
3.2.1 正常執行
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v1"
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"
3.2.2 放棄執行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v11
QUEUED
127.0.0.1:6379> set k2 v22
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
3.2.3 全部失敗
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> KEYS *
1) "k1"
2) "k2"
3.2.4 部分失敗
127.0.0.1:6379> KEYS *
1) "k1"
2) "k2"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k3 v33
QUEUED
127.0.0.1:6379> INCR k3
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
3) "v2"
4) "v33"
5) OK
127.0.0.1:6379> KEYS *
1) "k4"
2) "k1"
3) "k3"
4) "k2"
3.2.5 watch監控
- 悲觀鎖/樂觀鎖/CAS(Check And Set)
- 悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會block直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖
- 樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制。樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量,
- 樂觀鎖策略:提交版本必須大於記錄當前版本才能執行更新
- 操作
- 初始化信用卡可用餘額和欠額
- 無加塞篡改,先監控再開啟multi,保證兩筆金額變動在同一個事務內
- 有加塞篡改
- 監控了key,如果key被修改了,後面一個事務的執行失效
- unwatch
- 一旦執行了exec之前加的監控鎖都會被取消掉了
- 小結
- Watch指令,類似樂觀鎖,事務提交時,如果Key的值已被別的客戶端改變,比如某個list已被別的客戶端push/pop過了,整個事務佇列都不會被執行
- 通過WATCH命令在事務執行之前監控了多個Keys,倘若在WATCH之後有任何Key的值發生了變化,EXEC命令執行的事務都將被放棄,同時返回Nullmulti-bulk應答以通知呼叫者事務執行失敗
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> set dept 0
OK
127.0.0.1:6379> mget balance dept
1) "100"
2) "0"
127.0.0.1:6379> WATCH balance
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY balance 20
QUEUED
127.0.0.1:6379> INCRBY dept 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
127.0.0.1:6379> mget balance dept
1) "80"
2) "20"
127.0.0.1:6379> WATCH balance
OK
######################在另外一個終端執行########################
[[email protected] bin]# redis-cli -p 6379
127.0.0.1:6379> get balance
"80"
127.0.0.1:6379> set balance 800
OK
#######################結束,切回原來的終端執行#################
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY balance 20
QUEUED
127.0.0.1:6379> INCRBY dept 20
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> mget balance dept
1) "800"
2) "20"
127.0.0.1:6379> WATCH balance
OK
127.0.0.1:6379> set balance 500
OK
#####在另一個終端修改balance####
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set balance 100
QUEUED
127.0.0.1:6379> get balance
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> WATCH balance
OK
127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> get balance
"100"
127.0.0.1:6379> WATCH balance
OK
#####在另一個終端修改balance####
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set balance 100
QUEUED
127.0.0.1:6379> exec
(nil)
##一旦執行了exec之前加的監控鎖都會被取消掉了##
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set balance 100
QUEUED
127.0.0.1:6379> exec
1) OK
127.0.0.1:6379> get balance
"100"
3.3 總結
3.3.1 三階段
- 開啟:以MULTI開始一個事務
- 入隊:將多個命令入隊到事務中,接到這些命令並不會立即執行,而是放到等待執行的事務佇列裡面
- 執行:由EXEC命令觸發事務
3.3.2 三特性
- 執行:由EXEC命令觸發事務
- 單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷。
- 沒有隔離級別的概念:佇列中的命令沒有提交之前都不會實際的被執行,因為事務提交前任何指令都不會被實際執行,也就不存在”事務內的查詢要看到事務裡的更新,在事務外查詢不能看到”這個讓人萬分頭痛的問題
- 不保證原子性:redis同一個事務中如果有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾