Redis事務操作

zc發表於2021-06-13

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"

1

取消事務 (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)

3

錯誤示例

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

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)

4

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"

5

監控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

相關文章