Redis事務操作
Redis事務本質:
一組命令的集合 , 一個事務中的所有命令都會被
序列化
, 在事務執行過程中 , 會按照順序
執行
- 一次性 : 事務之間的事情,會一次性執行,而不是立刻執行
- 順序性 : 會按照順序進行執行
- 排他性 : 事務過程中,不允許被其他事情影響
Redis事務沒有隔離級別的概念
Redis單條命令儲存原子性 , 但事務不保證原子性
redis事務 :
- 開啟事務( multi )
- 命令入隊( 寫命令 )
- 執行事務( exec )
所以事務中的命令在加入時都沒有被執行,直到提交時才會開始執行( Exec )一次性完成
事務
正常流程
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> set k1 v1 # 存入 k1:v1
QUEUED
127.0.0.1:6379> set k2 v2 # 存入 k2:v2
QUEUED
127.0.0.1:6379> get k1 # 獲取k1對應的值
QUEUED
127.0.0.1:6379> set k3 v3 # 存入 k3:v3
QUEUED
127.0.0.1:6379> keys * # 檢視全部的key
QUEUED
127.0.0.1:6379> exec # 執行上面命令,下面是依次的結果
1) OK
2) OK
3) "v1"
4) OK
5) 1) "k3"
2) "k2"
3) "k1"
4) "sign"
取消事務 (discard)
如果你在執行之前取消事務,那麼你之前的操作都會取消,存入的元素也會當作沒存
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> set k1 v1 # 存入 k1:v1
QUEUED
127.0.0.1:6379> discard # 取消事務
OK
127.0.0.1:6379> exec # 執行事務,因為已經取消事務,會報錯
(error) ERR EXEC without MULTI
127.0.0.1:6379> get k1 # 獲取k1的值,但是取消事務了,k1為null
(nil)
錯誤示例
1.一次只能新增一個值
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> set k1 v1 k2 v2 # 存入 k1:v1、k2:v2
QUEUED
127.0.0.1:6379> keys * # 檢視全部的key
QUEUED
127.0.0.1:6379> exec # 執行上面命令
1) (error) ERR syntax error
2) (empty array)
2.程式碼語法錯誤
程式碼語法錯誤 ( 編譯時異常 ) , 所有的命令都不執行
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> set k v # 存入 k:v
QUEUED
127.0.0.1:6379> error k # 輸入了一個錯誤語句,報錯,而且看似沒影響後面的語句
(error) ERR unknown command `error`, with args beginning with: `k`,
127.0.0.1:6379> get k # 獲取k的值
QUEUED
127.0.0.1:6379> exec # 執行事務
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k # 事務已經結束,之後獲取k的值
(nil)
3.程式碼邏輯錯誤
程式碼邏輯錯誤 ( 執行時異常 ) , 其他命令可以正常執行
所以不保證事務原子性
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> set k v # 存入 k:v
QUEUED
127.0.0.1:6379> incr k # 元素k的值+1
QUEUED
127.0.0.1:6379> get k # 獲取k的值
QUEUED
127.0.0.1:6379> exec # 執行事務
1) OK
2) (error) ERR value is not an integer or out of range
3) "v"
監控watch
1.樂觀鎖、悲觀鎖
悲觀鎖:
- 很悲觀 , 認為什麼時候都會出現問題 , 所以無論做什麼都會加鎖
樂觀鎖:
- 很樂觀 , 認為什麼時候都不會出現問題 , 所以不會上鎖
可以採用的解決方法:
- 更新資料的時候去判斷一下 , 在此期間是否有人修改過這個資料
- 獲取version
- 更新的時候比較version
在Redis中可以採用:
使用watch key
監控指定資料 , 相當於樂觀鎖加鎖
2.正常執行
以下用操縱100元的例子進行模擬:
127.0.0.1:6379> set money 100 # 存入money100
OK
127.0.0.1:6379> set out 0 # 此時支出為0
OK
127.0.0.1:6379> watch money # 對money進行監控
OK
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> decrby money 10 # 使用了10元錢
QUEUED
127.0.0.1:6379> incrby out 10 # 支出的錢增加10元
QUEUED
127.0.0.1:6379> exec # 執行事務
1) (integer) 90
2) (integer) 10
測試多執行緒修改值 , 使用watch可以當做redis的樂觀鎖操作:
執行緒1:
127.0.0.1:6379> watch money # 對money進行監控
OK
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> decrby money 20 # 使用money20
QUEUED
127.0.0.1:6379> incrby out 20 # 支出增加20
QUEUED
127.0.0.1:6379>
線上程1沒執行事務的時候,執行緒2對money進行操作:
127.0.0.1:6379> incrby money 300 # 此時執行緒1還沒執行,增加money300
(integer) 390
此時,執行緒1執行事務:
127.0.0.1:6379> exec # 執行緒1執行,但是另一個執行緒修改了我們的值,這個時候就會導致事務執行失敗
(nil)
127.0.0.1:6379> get money # 因為事務執行失敗,所以只是執行緒2的money修改結果
"390"
127.0.0.1:6379> get out # 因為事務執行失敗,支出數值沒有被修改
"10"
個人部落格為:
MoYu's HomePage