最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2017年08月29日 10:30:09   作者:huangxincheng  
這篇文章主要介紹了redis事務(wù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

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

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

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

1. multi,exec

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

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

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

2. watch

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

WATCH
WATCH key [key ...]

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

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

 

二:原理探索

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

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)打開,告訴這個(gè)redis客戶端已經(jīng)進(jìn)入事務(wù)模式了。

2. 生成命令

在redisClient中,里面有一個(gè)multiState命令:

typedef struct redisClient {

  。。。

  multiState mstate;   /* MULTI/EXEC state */

  。。。

} redisClient;

從注釋中你大概也看到了這個(gè)命令和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這個(gè)枚舉中,你可以看到下面有一個(gè)*command命令,從注釋中可以看到它其實(shí)指向的是一個(gè)數(shù)組,它就是你的若干條命令啦。。。下面還有一個(gè)count,可以看到是實(shí)際的commands的總數(shù)。 

3. watch

為了方便說到后面的exec,這里想說一下watch大概是怎么實(shí)現(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);
 }

這段代碼中大概最核心的一點(diǎn)就是:

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

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

就是通過dicFetchValue這個(gè)字典方法,從watched_keys中找到指定key的value,而這個(gè)value是一個(gè)clients的鏈表,說明人家其實(shí)是想找到關(guān)于這個(gè)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是個(gè)字典結(jié)構(gòu),字典的鍵為上面的key1,key2。。。,value為client的鏈表,這樣的話,我就非常清楚某個(gè)key中是被哪些client監(jiān)視著的。

4.exec

這個(gè)命令里面大概做了兩件事情:

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

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

  

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

相關(guān)文章

  • redis5.0以上基于密碼認(rèn)證的集群cluster方式

    redis5.0以上基于密碼認(rèn)證的集群cluster方式

    這篇文章主要介紹了redis5.0以上基于密碼認(rèn)證的集群cluster方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Redis?Server啟動過程的詳細(xì)步驟

    Redis?Server啟動過程的詳細(xì)步驟

    本文主要介紹了Redis?Server啟動過程的詳細(xì)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 使用Redis如何設(shè)置永久有效

    使用Redis如何設(shè)置永久有效

    這篇文章主要介紹了使用Redis如何設(shè)置永久有效,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Redis+IDEA實(shí)現(xiàn)單機(jī)鎖和分布式鎖的過程

    Redis+IDEA實(shí)現(xiàn)單機(jī)鎖和分布式鎖的過程

    這篇文章主要介紹了Redis+IDEA實(shí)現(xiàn)單機(jī)鎖和分布式鎖的過程,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 使用redis如何生成自增序列號碼

    使用redis如何生成自增序列號碼

    這篇文章主要介紹了使用redis如何生成自增序列號碼,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Redis數(shù)據(jù)一致性問題的三種解決方案

    Redis數(shù)據(jù)一致性問題的三種解決方案

    Redis(Remote?Dictionary?Server?),是一個(gè)高性能的基于Key-Value結(jié)構(gòu)存儲的NoSQL開源數(shù)據(jù)庫,大部分公司采用Redis來實(shí)現(xiàn)分布式緩存,用來提高數(shù)據(jù)查詢效率,本文就給大家介紹三種Redis數(shù)據(jù)一致性問題的解決方案,需要的朋友可以參考下
    2023-07-07
  • redis實(shí)現(xiàn)的四種常見限流策略

    redis實(shí)現(xiàn)的四種常見限流策略

    因?yàn)樵诰W(wǎng)站運(yùn)行期間可能會因?yàn)橥蝗坏脑L問量導(dǎo)致業(yè)務(wù)異常、也有可能遭受別人惡意攻,所以我們對網(wǎng)站要進(jìn)行限流,本文主要介紹了redis四種常見限流策略,感興趣的可以了解一下
    2021-06-06
  • gem install redis報(bào)錯(cuò)的解決方案

    gem install redis報(bào)錯(cuò)的解決方案

    今天小編就為大家分享一篇關(guān)于gem install redis報(bào)錯(cuò)的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 詳解Redis單線程架構(gòu)的優(yōu)勢與不足

    詳解Redis單線程架構(gòu)的優(yōu)勢與不足

    很多人都遇到過這么一道面試題:Redis是單線程還是多線程?這個(gè)問題既簡單又復(fù)雜,說他簡單是因?yàn)榇蠖鄶?shù)人都知道Redis是單線程,說復(fù)雜是因?yàn)檫@個(gè)答案其實(shí)并不準(zhǔn)確,本文就給大家講講Redis單線程架構(gòu)的優(yōu)勢與不足,需要的朋友可以參考下
    2024-02-02
  • Redis實(shí)現(xiàn)用戶關(guān)注的項(xiàng)目實(shí)踐

    Redis實(shí)現(xiàn)用戶關(guān)注的項(xiàng)目實(shí)踐

    本文主要介紹了Redis實(shí)現(xiàn)用戶關(guān)注的項(xiàng)目實(shí)踐,通過使用Redis的set數(shù)據(jù)結(jié)構(gòu)來存儲關(guān)注對象,方便高效地進(jìn)行添加和取消關(guān)注操作,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02

最新評論

天柱县| 新津县| 清河县| 方城县| 郴州市| 德钦县| 读书| 吉水县| 灯塔市| 绥中县| 当雄县| 北京市| 安图县| 烟台市| 绥芬河市| 宝坻区| 广南县| 临夏县| 乡宁县| 新闻| 南召县| 江都市| 开远市| 马公市| 桃江县| 额敏县| 通化县| 陵川县| 昆山市| 旺苍县| 于田县| 阿荣旗| 岚皋县| 自贡市| 陆川县| 石嘴山市| 义乌市| 麻栗坡县| 姚安县| 祁连县| 巫山县|