天天看點

15天玩轉redis —— 第八篇 你不得不會的事務玩法

我們都知道redis追求的是簡單,快速,高效,在這種情況下也就拒絕了支援window平台,學sqlserver的時候,我們知道事務還算是個比較複雜的東西,

是以這吊毛要是照搬到redis中去,理所當然redis就不是那麼簡單純碎的東西了,但是呢,事務是我們寫程式無法逃避的場景,是以redis作者折衷的寫了個簡

化版的事務機制,下面我來扯一下它的蛋蛋。

一: 事務實戰

  具體到事務是什麼,要保證什麼。。。這個我想沒必要說了,先不管三七二十一,看一下redis手冊,領略下它的魔力。

15天玩轉redis —— 第八篇 你不得不會的事務玩法

1. multi,exec

   還記得sqlserver是怎麼玩的嗎?一般都是這樣的三個步驟,生成事務,産生指令,執行事務,對吧,而對應redis呢??multi就是生成事務,然後

輸入redis指令,最後用exec執行指令,就像下面這樣:

15天玩轉redis —— 第八篇 你不得不會的事務玩法

可以看到,我set完指令之後,回報資訊是queued,最後我再執行exec,這些指令才會真正的執行,就是這麼的簡單,一切執行的就是那麼的順利,

一點都不拖泥帶水,牛逼的不要不要的,可能有些人說,其實事務中還有一個rollback操作,但好像在redis中沒有看到,哈哈,牛逼哈,很遺憾是

redis中沒有rollback操作,比如下面這樣。

15天玩轉redis —— 第八篇 你不得不會的事務玩法

在圖中我故意用lpush指令去執行string,可想而知自然不會執行成功,但從結果中,你看到什麼了呢?兩個ok,一個error,這就是違反了事務

的原子性,對吧,但是我該怎麼反駁呢??? 我會說,錯你妹啊。。。連個基本的指令都寫錯了,你搞個毛啊。。。還寫個吊毛代碼,reids僅僅

是個資料結構伺服器,多簡單的一件事情,退一萬步說,很明顯的錯誤指令它會直接傳回的,比如我故意把lpush寫成lpush1:

15天玩轉redis —— 第八篇 你不得不會的事務玩法

2. watch

  不知道你看完multi後面的三條set指令之後,有沒有一種心虛的感覺,怎麼說呢,就是隻要指令是正确的,redis保證會一并執行,誓死完成

任務,雖然說指令是一起執行的,但是誰可以保證我在執行指令的過程中,其他client不會修改這些值呢???如果修改了這些值,那我的exec

還有什麼意義呢???沒關系,這種爛大街的需求,redis怎可能袖手旁觀???這裡的watch就可以助你一臂之力。

 上面就是redis手冊中關于watch的解釋,使用起來貌似很簡單,就是我在multi之前,用watch去監視我要修改的key,如果說我在exec之前,

multi之後的這段時間,key被其他client修改,那麼exec就會執行失敗,傳回(nil),就這麼簡單,我還是來舉個例子:

15天玩轉redis —— 第八篇 你不得不會的事務玩法

二:原理探索

  關于事務操作的源代碼,大多都在redis源碼中的multi.c 檔案中,接下來我會一個一個的簡單剖析一下:

1. multi

  在redis的源代碼中,它大概是這麼寫的:

從這段代碼中,你可以看到multi隻是簡單的把redisclient的redis_multi狀态打開,告訴這個redis用戶端已經進入事務模式了,對吧。

2. 生成指令

在redisclient中,裡面有一個multistate指令:

從注釋中你大概也看到了這個指令和multi/exec肯定有關系,接下來我很好奇的看看multistate的定義:

從multistate這個枚舉中,你可以看到下面有一個*command指令,從注釋中可以看到它其實指向的是一個數組,這個數組我想你閉着眼睛都

能想得到吧。。。它就是你的若幹條指令啦。。。下面還有一個count,可以看到是實際的commands的總數。

3. watch

    為了友善說到後面的exec,這裡想說一下watch大概是怎麼實作的,在multi.c源代碼中是這樣寫的。

這段代碼中大概最核心的一點就是:

就是通過dicfetchvalue這個字典方法,從watched_keys中找到指定key的value,而這個value是一個clients的連結清單,說明人家其實是想找到

關于這個key的所有client,對吧,最後還會将本次key塞入到redisclient的watched_keys字典中,如下代碼:

如果非要畫圖,大概就是這樣:

15天玩轉redis —— 第八篇 你不得不會的事務玩法

其中watched_key是個字典結構,字典的鍵為上面的key1,key2。。。,value為client的連結清單,這樣的話,我就非常清楚某個key

中是被哪些client監視着的,對吧。

4.exec

    這個指令裡面大概做了兩件事情:

<1>:   判斷c->flags=redis_dirty_exec 打開與否,如果是的話,取消事務discardtransaction(c),也就是說這個key已經

          被别的client修改了。

<2>:   如果沒有修改,那麼就for循環執行comannd[]中的指令,如下圖中的兩處資訊:

  

15天玩轉redis —— 第八篇 你不得不會的事務玩法

好了,大概就這麼說了,希望對你有幫助哈~~~

繼續閱讀