日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redis watch使用场景_redis不得不会的事务玩法

發布時間:2023/12/4 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis watch使用场景_redis不得不会的事务玩法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

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

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

一: 事務實戰

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

1. multi,exec

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

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

可以看到,我set完命令之后,反饋信息是QUEUED,最后我再執行exec,這些命令才會真正的執行,就是這么的簡單,一切執行的就是那么的順利,

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

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

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

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

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

2. watch

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

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

還有什么意義呢???沒關系,這種爛大街的需求,redis怎可能袖手旁觀???這里的watch就可以助你一臂之力。WATCHWATCH?key?[key?...]監視一個(或多個)?key?,如果在事務執行之前這個(或這些)?key?被其他命令所改動,那么事務將被打斷。

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

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

二:原理探索

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

1. multi

在redis的源代碼中,它大概是這么寫的:1?void?multiCommand(redisClient?*c)?{

2?????if?(c->flags?&?REDIS_MULTI)?{

3?????????addReplyError(c,"MULTI?calls?can?not?be?nested");

4?????????return;

5?????}

6?????c->flags?|=?REDIS_MULTI;

7?????addReply(c,shared.ok);

8?}

從這段代碼中,你可以看到multi只是簡單的把redisClient的REDIS_MULTI狀態打開,告訴這個redis客戶端已經進入事務模式了,對吧。

2. 生成命令

在redisClient中,里面有一個multiState命令:typedef?struct?redisClient?{

。。。

multiState?mstate;??????/*?MULTI/EXEC?state?*/

。。。

}?redisClient;

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

multiCmd?*commands;?????/*?Array?of?MULTI?commands?*/

int?count;??????????????/*?Total?number?of?MULTI?commands?*/

int?minreplicas;????????/*?MINREPLICAS?for?synchronous?replication?*/

time_t?minreplicas_timeout;?/*?MINREPLICAS?timeout?as?unixtime.?*/

}?multiState;

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

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

3. watch

為了方便說到后面的exec,這里想說一下watch大概是怎么實現的,在multi.c源代碼中是這樣寫的。1?typedef?struct?watchedKey?{

2?????robj?*key;

3?????redisDb?*db;

4?}?watchedKey;

5

6?void?watchCommand(redisClient?*c)?{

7?????int?j;

8

9?????if?(c->flags?&?REDIS_MULTI)?{

10?????????addReplyError(c,"WATCH?inside?MULTI?is?not?allowed");

11?????????return;

12?????}

13?????for?(j?=?1;?j?argc;?j++)

14?????????watchForKey(c,c->argv[j]);

15?????addReply(c,shared.ok);

16?}

17

18?/*?Watch?for?the?specified?key?*/

19?void?watchForKey(redisClient?*c,?robj?*key)?{

20?????list?*clients?=?NULL;

21?????listIter?li;

22?????listNode?*ln;

23?????watchedKey?*wk;

24

25?????/*?Check?if?we?are?already?watching?for?this?key?*/

26?????listRewind(c->watched_keys,&li);

27?????while((ln?=?listNext(&li)))?{

28?????????wk?=?listNodeValue(ln);

29?????????if?(wk->db?==?c->db?&&?equalStringObjects(key,wk->key))

30?????????????return;?/*?Key?already?watched?*/

31?????}

32?????/*?This?key?is?not?already?watched?in?this?DB.?Let's?add?it?*/

33?????clients?=?dictFetchValue(c->db->watched_keys,key);

34?????if?(!clients)?{

35?????????clients?=?listCreate();

36?????????dictAdd(c->db->watched_keys,key,clients);

37?????????incrRefCount(key);

38?????}

39?????listAddNodeTail(clients,c);

40?????/*?Add?the?new?key?to?the?list?of?keys?watched?by?this?client?*/

41?????wk?=?zmalloc(sizeof(*wk));

42?????wk->key?=?key;

43?????wk->db?=?c->db;

44?????incrRefCount(key);

45?????listAddNodeTail(c->watched_keys,wk);

46?}

這段代碼中大概最核心的一點就是:/*?This?key?is?not?already?watched?in?this?DB.?Let's?add?it?*/

clients?=?dictFetchValue(c->db->watched_keys,key);

就是通過dicFetchValue這個字典方法,從watched_keys中找到指定key的value,而這個value是一個clients的鏈表,說明人家其實是想找到

關于這個key的所有client,對吧,最后還會將本次key塞入到redisclient的watched_keys字典中,如下代碼:/*?Add?the?new?key?to?the?list?of?keys?watched?by?this?client?*/

wk?=?zmalloc(sizeof(*wk));

wk->key?=?key;

wk->db?=?c->db;

incrRefCount(key);

listAddNodeTail(c->watched_keys,wk);

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

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

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

4.exec

這個命令里面大概做了兩件事情:

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

被別的client修改了。

<2>: ? 如果沒有修改,那么就for循環執行comannd[]中的命令,如下圖中的兩處信息:

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

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的redis watch使用场景_redis不得不会的事务玩法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。