文章目錄
- 一、什么是事務?
- 二、事務相關操作
- 總體認識
- 基本操作流程
- watch 操作演示
- watch 原理
一、什么是事務?
Redis 的事務和 MySQL 的事務概念上是類似的. 都是把?系列操作綁定成?組. 讓這?組能夠批量執?.
Redis 的事務和 MySQL 事務的區別:
- 弱化的原?性: redis 沒有 “回滾機制”. 只能做到這些操作 “批量執?”. 不能做到 “?個失敗就恢復到初始狀態”.
- 不保證?致性: 不涉及 “約束”. 也沒有回滾. MySQL 的?致性體現的是運?事務前和運?后結果都是合理有效的, 不會出現中間?法狀態.
- 不需要隔離性: 也沒有隔離級別, 因為不會并發執?事務 (redis 單線程處理請求) .
- 不需要持久性: 是保存在內存的. 是否開啟持久化, 是redis-server ??的事情, 和事務?關.
關于 Redis 事務原子性的爭議
爭議點主要在于 原子性 的定義到底是把命令打包一起執行即可還是在此基礎上必須具備 MySQL事務的回滾機制
Redis 事務理解
Redis 事務本質上是把一系列命令插入到 “事務隊列中”。每次客戶端在事務中進??個操作, 都會把命令先發給服務器, 放到 “事務隊列” 中(但是并不會立即執行)。等遇到 EXEC 命令之后,才會按照隊列順序依次執行命令。
Redis 事務的使用場景
秒殺(搶票)
在搶票場景中需要注意的是 “超賣” 問題。就比如我最多只能 500 張票,但我的買票系統讓 501 個人都買到票了,這就是“超賣”問題。這種問題是由于線程競爭資源導致的。傳統的解決方式是加鎖,這里介紹通過 Redis 事務解決方案。
使用 redis 事務機制的話,就可以把 獲取票數、判斷 票數大于 0和票數減一 這三個操作打包成一個事務,再加上 Redis 服務器本身是 單線程模型,這樣就可以保證不會出現競爭資源導致的超賣問題。
二、事務相關操作
總體認識
事務的核心操作就是 MULTI(開啟事務)、EXEC(真正執行事務)、DISCARD(放棄事務)、WATCH(監控 key 的變化)
- MULTI : 開啟一個事務,執行成功返回 OK
- EXEC: 執行這條命令后,將真正執行 “事務隊列” 中存放的命令
- DISCARD: 放棄當前事務,即服務器收到這條命令就會清空隊列。之前的操作都不會執行。
- WATCH : 監控某個 key 的值的變化,防止數據不一致問題。這條命令后面專門講。
基本操作流程
- 開啟事務,執行基本的命令。
- 此時,我們可以新開一個客戶端查看一下 key1 key2 ,此時key1 key2 仍然為空。
- 執行 exec 命令,逐條得到事務中命令的返回值
- 之后進行查詢就能看到值了
discard 操作:
watch 操作演示
問題場景:
- 客戶端 1 開啟事務,執行 set k1 111。
- 在客戶端 1 執行 exec 之前,客戶端 2 執行 set k1 222
- 客戶端1 執行 exec
問,此時的 k1 的值?
答案是:111。這是因為set k1 111 實際在 exec 命令之后才會執行,會覆蓋客戶端2 執行的set k1 222,所以最終的值是 111。
場景示例:
- 客戶端 1 開啟事務,執行 set k1 111。
- 在客戶端 1 執行 exec 之前,客戶端 2 執行 set k1 222
- 客戶端1 執行 exec,查看 k1 的值
這樣就會存在一定的歧義,引入 watch 操作,就能避免上述問題:
WATCH key1 [key2 key3 ...]
原理:
- 當開啟事務的時候, 如果對 watch 的 key 進?修改, 就會記錄當前 key 的 “版本號”. (版本號是個簡單的整數, 每次修改都會使版本變?. 服務器來維護每個 key 的版本號情況)
- 在真正提交事務的時候, 如果發現當前服務器上的 key 的版本號已經超過了事務開始時的版本號, 就會讓事務執?失敗. (事務中的所有操作都不執?).
演示:
- 刪除 k1 防止之前值的干擾,客戶端1 先watch k1 再開啟事務,執行 set k1 111。
- 客戶端 2 執行 set k1 222
- 客戶端1 執行 exec ,再查看 k1 的值
watch 原理
Redis 的 WATCH 命令是實現樂觀鎖的核心機制,用于在事務執行前監控指定的鍵,確保事務執行的原子性和一致性。其底層原理可以總結為以下幾個關鍵點:
-
版本號機制
- Redis 為每個鍵(key)維護一個版本號(本質是一個整數計數器)。
- 每當鍵被修改(無論是通過
SET
、INCR
等命令),其版本號會自動加 1。 - 版本號由 Redis 服務器在底層自動管理,用戶無需手動干預
-
監控鍵的版本快照
- 當執行
WATCH key1 [key2 ...]
時,Redis 會記錄當前被監控鍵的最新版本號,形成一個“版本快照”。
- 當執行
-
事務執行的版本校驗
- 執行 WATCH 后,用戶通過
MULTI
開啟事務,然后編寫一系列命令(如SET
、HSET 等)。 - 當通過 EXEC 提交事務時,Redis 會做一次版本校驗:
- 檢查所有被 WATCH 的鍵,當前服務器上的版本號是否與 WATCH 時記錄的“版本快照”一致。
- 如果全部一致:說明事務期間沒有其他客戶端修改這些鍵,事務正常執行,所有命令生效。
- 如果有任何一個鍵的版本號不一致:說明該鍵被其他客戶端修改過,事務整體取消(所有命令都不執行),
EXEC
返回nil
表示事務失敗。
- 執行 WATCH 后,用戶通過
-
樂觀鎖的體現
WATCH
的設計基于“樂觀鎖”思想:默認認為事務執行期間不會有并發修改,因此不主動加鎖阻塞其他操作。- 只有在提交時通過版本號比對發現沖突,才放棄執行,避免了悲觀鎖的性能開銷。