你應該知道的Redis事務

七淅在學Java發表於2022-03-29

大家好,我是七淅。

如果你瞭解過關係型資料庫事務的話,相信這篇文章對你來說是很容易理解的了。具體什麼是事務我就不說不多了,直接講 Redis 事務相關的部分。

首先,我們先來看下,Redis 是怎麼執行事務的。

1. 事務執行過程

show code:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a test1
QUEUED
127.0.0.1:6379> set b test2
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
127.0.0.1:6379> get a
"test1"
127.0.0.1:6379> get b
"test2"

一個事務的開始到結束會經過以下 3 個過程

  1. 事務開始
  2. 命令入隊
  3. 事務執行

結合上面的例子,用人話介紹這 3 個過程就是:

Redis 執行 multi 命令標誌事務開始。

當客戶端切換至事務狀態後,服務端會將除了 exec、discard(取消事務,放棄執行事務塊內的所有命令)、watch 和 multi 以外的命令放進一個先進先出的事務佇列中。即上面例子的 2 個 set 命令會被放進佇列,並返回 QUEUED 給客戶端。

當客戶端傳送 exec 命令時,服務端會立即執行該命令。遍歷這個客戶端的事務佇列,執行佇列儲存的所有命令。最後將執行命令所得結果返回給客戶端。

2. Redis 事務和關係型事務的區別

兩者最大區別就是 Redis 事務不支援回滾。即使事務佇列中某個命令在執行期間發生了錯誤,事務也會繼續執行,直到事務佇列中所有命令執行完成。

文字貌似不夠直觀,沒事,看下面的例子你就馬上明白了。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set msg test
QUEUED
127.0.0.1:6379> lpop msg
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get msg
"test"      // 不受後面錯誤命令影響

PS:如果客戶端向事務入列一個錯誤的命令(比如輸入一個不存在的命令,像:sett 命令),那麼該事務將不被服務端執行。該情況是入隊錯誤,上面例子是執行錯誤的情況。

3. watch

提到 redis 事務,就不得不提 watch 命令了。

該命令是一個樂觀鎖,只能在客戶端進入事務狀態之前執行。

作用是 exec 命令執行之前,監視任何數量個鍵,並在 exec 命令執行時,檢查被監視的鍵是否至少有一個已經被修改過。若是則拒絕執行事務,否則執行。

當 exec 執行完成後,這次事務也就結束了。

我們依舊來看一個簡單的栗子:

127.0.0.1:6379> SET msg test  //設定 msg 的值
OK
127.0.0.1:6379> WATCH msg //監視 msg
OK
127.0.0.1:6379> SET msg test2 //修改 msg 的值(或其他客戶端在該客戶端執行 exec 命令之前修改該值)
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET msg test3
QUEUED
127.0.0.1:6379> GET msg
QUEUED
127.0.0.1:6379> EXEC 
(nil)   //執行失敗

如果覺得文章不錯,希望能得到你的關注:七淅在學Java

相關文章