麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 數(shù)據(jù)庫 > Redis > 正文

redis事務(wù)_動力節(jié)點Java學院整理

2020-10-28 21:35:53
字體:
供稿:網(wǎng)友

我們都知道redis追求的是簡單,快速,高效,在這種情況下也就拒絕了支持window平臺,學sqlserver的時候,我們知道事務(wù)還算是個比較復雜的東西,所以這要是照搬到redis中去,理所當然redis就不是那么簡單純碎的東西了,但是呢,事務(wù)是我們寫程序無法逃避的場景,所以redis作者折衷的寫了個簡化版的事務(wù)機制。

一: 事務(wù)實戰(zhàn)

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

1. multi,exec

還記得sqlserver是怎么玩的嗎?一般都是這樣的三個步驟,生成事務(wù),產(chǎn)生命令,執(zhí)行事務(wù),對吧,而對應(yīng)redis呢??multi就是生成事務(wù),然后輸入redis命令,最后用exec執(zhí)行命令,就像下面這樣:

可以看到,我set完命令之后,反饋信息是QUEUED,最后我再執(zhí)行exec,這些命令才會真正的執(zhí)行,就是這么的簡單,一切執(zhí)行的就是那么的順利,一點都不拖泥帶水,可能有些人說,其實事務(wù)中還有一個rollback操作,但好像在redis中沒有看到,很遺憾是redis中沒有rollback操作,比如下面這樣。

在圖中我故意用lpush命令去執(zhí)行string,可想而知自然不會執(zhí)行成功,但從結(jié)果中,你看到什么了呢?兩個OK,一個Error,這就是違反了事務(wù)的原子性,但是我該怎么反駁呢??? reids僅僅是個數(shù)據(jù)結(jié)構(gòu)服務(wù)器,多簡單的一件事情,退一萬步說,很明顯的錯誤命令它會直接返回的,比如我故意把lpush寫成lpush1:

2. watch

不知道你看完multi后面的三條set命令之后,有沒有一種心虛的感覺,怎么說呢,就是只要命令是正確的,redis保證會一并執(zhí)行,誓死完成任務(wù),雖然說命令是一起執(zhí)行的,但是誰可以保證我在執(zhí)行命令的過程中,其他client不會修改這些值呢???如果修改了這些值,那我的exec還有什么意義呢???沒關(guān)系,這種爛大街的需求,redis怎可能袖手旁觀???這里的watch就可以助你一臂之力。

WATCHWATCH key [key ...]

監(jiān)視一個(或多個) key ,如果在事務(wù)執(zhí)行之前這個(或這些) key 被其他命令所改動,那么事務(wù)將被打斷。

上面就是redis手冊中關(guān)于watch的解釋,使用起來貌似很簡單,就是我在multi之前,用watch去監(jiān)視我要修改的key,如果說我在exec之前,multi之后的這段時間,key被其他client修改,那么exec就會執(zhí)行失敗,返回(nil),就這么簡單,我還是來舉個例子:

 

二:原理探索

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

1. multi

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

void multiCommand(redisClient *c) {   if (c->flags & REDIS_MULTI) {     addReplyError(c,"MULTI calls can not be nested");     return;   }   c->flags |= REDIS_MULTI;   addReply(c,shared.ok);

從這段代碼中,你可以看到multi只是簡單的把redisClient的REDIS_MULTI狀態(tài)打開,告訴這個redis客戶端已經(jīng)進入事務(wù)模式了。

2. 生成命令

在redisClient中,里面有一個multiState命令:

typedef struct redisClient {  。。。  multiState mstate;   /* MULTI/EXEC state */  。。。} redisClient;

從注釋中你大概也看到了這個命令和multi/exec肯定有關(guān)系,接下來我很好奇的看看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命令,從注釋中可以看到它其實指向的是一個數(shù)組,它就是你的若干條命令啦。。。下面還有一個count,可以看到是實際的commands的總數(shù)。 

3. watch

為了方便說到后面的exec,這里想說一下watch大概是怎么實現(xiàn)的,在multi.c源代碼中是這樣寫的。

typedef struct watchedKey {   robj *key;   redisDb *db; } watchedKey;  void watchCommand(redisClient *c) {   int j;    if (c->flags & REDIS_MULTI) {     addReplyError(c,"WATCH inside MULTI is not allowed");     return;   }   for (j = 1; j < c->argc; j++)     watchForKey(c,c->argv[j]);   addReply(c,shared.ok); }  /* Watch for the specified key */ void watchForKey(redisClient *c, robj *key) {   list *clients = NULL;   listIter li;   listNode *ln;   watchedKey *wk;    /* Check if we are already watching for this key */   listRewind(c->watched_keys,&li);   while((ln = listNext(&li))) {     wk = listNodeValue(ln);     if (wk->db == c->db && equalStringObjects(key,wk->key))       return; /* Key already watched */   }   /* This key is not already watched in this DB. Let's add it */   clients = dictFetchValue(c->db->watched_keys,key);   if (!clients) {     clients = listCreate();     dictAdd(c->db->watched_keys,key,clients);     incrRefCount(key);   }   listAddNodeTail(clients,c);   /* 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); }

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

  /* 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的鏈表,說明人家其實是想找到關(guān)于這個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是個字典結(jié)構(gòu),字典的鍵為上面的key1,key2。。。,value為client的鏈表,這樣的話,我就非常清楚某個key中是被哪些client監(jiān)視著的。

4.exec

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

<1>:   判斷c->flags=REDIS_DIRTY_EXEC 打開與否,如果是的話,取消事務(wù)discardTransaction(c),也就是說這個key已經(jīng)被別的client修改了。

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

  

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

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 黄片毛片一级 | 亚洲第一色婷婷 | 27xxoo无遮挡动态视频 | 亚洲日本高清 | 久久久久久免费 | 蜜桃麻豆视频 | 欧洲色阁中文字幕 | 欧美特黄a | 一区二区三区在线观看免费视频 | 青青草免费观看 | 亚洲第一激情网 | 国产成人免费精品 | 久久国产精品二区 | av一道本 | 国产99久久精品一区二区 | 本色视频aaaaaa一级网站 | 国产91精品久久久久久 | 欧美国产精品一区二区 | 天天草天天爱 | 久久视频精品 | 免费的性生活视频 | 国产精品久久久久久久模特 | 91专区在线观看 | 国产成人自拍小视频 | 久久福利在线 | 国产无遮挡一区二区三区毛片日本 | 羞羞的动漫在线观看 | 91午夜少妇三级全黄 | 毛片免费视频网站 | 久久精品国产99国产精品澳门 | 午夜视频在线看 | 91福利国产在线观一区二区 | 欧美日韩影视 | 黄色免费播放网站 | 日日鲁夜夜视频热线播放 | 18欧美性xxxx极品hd | 欧美福利视频一区二区三区 | 亚洲第五色综合网 | 国产一区视频免费观看 | 国产1区2| 91久久极品少妇韩国 |