編程界的小學生
一、介紹
Redis的事務並不像Mysql那麼靈活,有隔離級別,出問題後還能回滾數據等高級操作。Redis畢竟是非關係型數據庫,他目前事務回滾機制是不執行命令,也就是可以採取watch命令模擬樂觀鎖,進行監聽數據,發現數據不是事務開始時候的樣子了,那麼我這個事務裏的命令就不會得到執行。
二、三大命令
首先看下事務的全部命令
但核心的命令就三個
- MULTI:開始事務。
- EXEC:執行事務,也就是說只有EXEC命令執行的時候,這個事務內的語句纔會真正的得到執行。
- WATCH:監聽數據變化,在開始事務之前執行。
三、實戰
1、MULTI/EXEC
1.1、描述
誰的exec先到達先處理誰的事務,比如有2個客戶端,第一個發送mutil開啓事務,然後執行了get k1操作,第二個客戶端同樣發送mutil開啓事務,然後執行了del k1操作。由於redis是單進程單線程的,所以這兩個client發送的命令執行肯定有先後順序,那麼哪個先執行呢?完全取決於exec命令,看exec命令哪個先到達先處理哪個。比如1的exec先到達,那就先get,然後client2的exec到了則在處理del。
1.2、圖示
1.3、代碼
# 先設置k1爲2
set k1 2
# 客戶端1
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> get k1
QUEUED
# 客戶端2
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> del k1
QUEUED
# 然後客戶端2執行exec
127.0.0.1:6380> EXEC
1) (integer) 1
# 然後客戶端1執行exec,結果發現nil了,被刪了。 類似於mysql中的讀已提交。不是RR。
127.0.0.1:6380> EXEC
1) (nil)
2、WATCH/MULTI/EXEC
2.1、描述
樂觀鎖的功能,比如先發送watch進行監聽到當前k1的值是3,然後開啓事務,執行 get k1,這時候 exec還沒執行,所以整個事務不會執行。在這期間client2執行了set k1 4(下圖是del語句,一樣的盜裏),且exec先到達執行完畢了。這時候client1再執行exec的時候發現k1的值已經變化了,則redis會爲我們回滾這條語句,不進行執行client1的事務。
2.2、圖示
2.3、代碼
set k1 2
# 客戶端1
127.0.0.1:6380> watch k1
OK
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> set k1 5
QUEUED
127.0.0.1:6380> get k1
QUEUED
# 客戶端2
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> set k1 adasdad
QUEUED
# 提交客戶端2的事務
127.0.0.1:6380> exec
1) OK
# 提交客戶端1的事務,發現報錯了。redis裏面不會有異常,只會有語法錯誤,nil在這裏就可以理解這個事務沒執行,因爲他監測到k1數據變化了
127.0.0.1:6380> exec
(nil)
3、說明
- 開啓事務後每次執行命令都返回一個QUEUE,代表開啓事務後每個命令都在queue裏,並沒有得到執行,exec後才執行
- watch監聽到數據有變化,則命令不會執行。返回了nil,疑問:爲什麼nil不是事務裏命令的正常返回值呢? 我們事務裏兩個命令,他只返回了一個nil,有頭皮屑想也是命令沒得到執行。否則就返回兩條結果了。
四、總結
- 介紹&&與mysql事務區別
- WATCH/MULTI/EXEC的作用
- 實戰
- 事務開啓後,每次執行命令都是放到QUEUE
五、個人公衆號
微信公衆號【Java碼農社區】