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[]中的命令,如下圖中的兩處信息:

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282106.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282106.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282106.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

加快Android Studio的編譯速度

從Eclipse切換到Android Studio后&#xff0c;感覺Android Studio的build速度比Eclipse慢很多&#xff0c;以下幾個方法可以提高Android Studio的編譯速度使用Gradle 2.4Gradle 2.4對執行性能有很大的優化&#xff0c;但Android Studio現在默認使用的是Gradle 2.2,所以我們需要…

開發中 MySQL 規范

一、建表規范 1、數據庫名、表名、字段名必須使用小寫字母或數字&#xff0c;并且禁止以數字開頭 示例&#xff1a;goods_category、agent_operate_201812_log 2、數據庫名、表名、字段名要做到見名識意 示例&#xff1a;goods_category&#xff0c;不能 gc 3、配置表建議以 …

PaddleOCR在 Linux下的webAPI部署方案

很多小伙伴在使用OCR時都希望能采用API的方式調用&#xff0c;這樣就可以跨端跨平臺了。本文將介紹一種基于python的PaddleOCR識別WebAPI部署方案。喜歡的可以關注公眾號&#xff0c;獲取更多內容。一、 Linux環境下部署1.環境要求操作系統&#xff1a;CenterOS7&#xff1b;主…

影響程序員生涯的三個錯誤觀念,你千萬不要犯!

程序員在社會上&#xff0c;到底是怎樣一個生活群體&#xff1f;是否能找到自己方向&#xff1f;其實&#xff0c;路一直都在那里&#xff0c;只是你看不到而已&#xff01; 當初的你&#xff0c;可能一直被一些技術牽著鼻子走&#xff0c;并不是自己在做著自己想做的&#xff…

心電圖計算心率公式_心電圖到底能反應啥問題,看過之后你也能當“醫生”

只要是經歷過健康體檢的健康人&#xff0c;或者做過手術的患者&#xff0c;基本都做過心電圖檢查。都說久病成醫&#xff0c;所以有些人對血、尿常規等各項檢查的結果都門清兒得很&#xff0c;最起碼看一眼也能說出個大概齊。偏偏心電圖這種常做的檢查&#xff0c;不但老病號如…

獲取正在運行的服務

手機上安裝的App&#xff0c;在后臺運行著很多不同功能的服務&#xff0c;最常見的例如消息推送相關的服務。如何查看這些服務&#xff1f;如何判斷某個服務是否正在運行&#xff1f;如何停止某一個服務呢&#xff1f;請看下面的方法&#xff1a; package com.example.servicel…

openstack的vnc啟動ssl

1、制作ssl證書# cd /etc/pki/tls/certs [rootwww certs]# make vnc.key Enter pass phrase:# 輸入密碼 Verifying - Enter pass phrase:#確認# 從private key 中刪除密碼# openssl rsa -in vnc.key -out vnc.key # make vnc.csr Country Name (2 letter code) [XX]:CN# 國家 S…

開發composer包

一、初始化&#xff08;生成composer.json文件&#xff09; composer init#輸入你要創建的composer包項目命名空間 Package name (<vendor>/<name>) [root/tiny-laravel]: #haveyb/tiny-laravel #輸入composer包的描述 Description []:#this is a tiny laravel h…

Linux本地yum源配置以及使用yum源安裝gcc編譯環境

本文檔是圖文安裝本地yum源的教程&#xff0c;以安裝gcc編譯環境為例。 適用范圍&#xff1a;所有的cetos,紅帽,fedroa版本 適用人群&#xff1a;有一點linux基礎的小白 范例系統版本&#xff1a;CentOS Linux release 7.3.1611 (Core) 范例環境&#xff1a;vmware 虛擬機 安裝…

word如何設置上標形式_如何在word中設置特殊頁碼

獲取更多業界資訊和深度好文● 點擊藍字關注我們 ●在日常工作中&#xff0c;我們編輯的word文檔經常需要設置頁碼&#xff0c;但有時文檔的第一頁是封面&#xff0c;第二頁才是正文&#xff0c;或者第二頁是目錄&#xff0c;第三頁才是正文&#xff0c;如下圖所示&#xff0c;…

[cf797c]Minimal string(貪心+模擬)

題意&#xff1a; 給出了字符串s的內容&#xff0c;字符串t&#xff0c;u初始默認為空&#xff0c;允許做兩種操作&#xff1a; 1、把s字符串第一個字符轉移到t字符串最后 2、把t字符串最后一個字符轉移到u字符串最后 最后要求s、t字符串都為空&#xff0c;問u字符串字典序最小…

發布composer包到 Packagist,并設置自動同步(從github到Packagist)

一、發布composer包 1、將我們寫好的項目包發布到github上 這一步不贅述&#xff0c;應該都會。 但是需要注意的是&#xff0c;我們一定要為我們的項目包打上tag之后再提交&#xff0c;否則 我們composer require時可能會報錯 Could not find a version of package。 # 設置…

教你在CorelDRAW中導入位圖

在CorelDRAW軟件中不能直接打開位圖圖像&#xff0c;在實際操作中&#xff0c;用戶需要使用導入位圖圖像的方法進行操作。導入位圖圖像時&#xff0c;可以導入整幅圖像&#xff0c;也可以在導入的過程中對圖像進行裁剪&#xff0c;或重新取樣圖像&#xff0c;導入整幅位圖圖像時…

.NET 6 中將 ASP.NET Core 注冊成 Windows Service

前言使用 Visual Studio 中的 Worker Service項目模板:我們很容易創建出 Windows Service&#xff1a;IHost host Host.CreateDefaultBuilder(args).UseWindowsService().ConfigureServices(services >{services.AddHostedService<Worker>();}).Build();await host.R…

19.12 添加自定義監控項目 配置郵件告警 測試告警

9月12日任務19.12 添加自定義監控項目19.13/19.14 配置郵件告警19.15 測試告警19.16 不發郵件的問題處理19.12 添加自定義監控項目需求&#xff1a;監控某臺web的80端口連接數&#xff0c;并出圖兩步&#xff1a;1&#xff09;zabbix監控中心創建監控項目&#xff1b;2&#xf…

wab框架

http協議 一、http簡介 1.HTTP是一個基于TCP/IP通信協議來傳遞數據&#xff08;HTML 文件, 圖片文件, 查詢結果等&#xff09;。 2.HTTP是一個屬于應用層的面向對象的協議&#xff0c;由于其簡捷、快速的方式&#xff0c;適用于分布式超媒體信息系統。它于1990年提出&#xff0…

c++ 二維矩陣 轉vector_Python線性代數學習筆記——矩陣的基本運算和基本性質,實現矩陣的基本運算...

當學習完矩陣的定義以后&#xff0c;我們來學習矩陣的基本運算&#xff0c;與基本性質矩陣的基本運算&#xff1a;矩陣的加法&#xff0c;每一個對應元素相加&#xff0c;對應結果的矩陣例子&#xff1a;矩陣A和矩陣B表示的是同學上學期和下學期的課程的成績&#xff0c;兩個矩…

android 4.4以上能夠實現的沉浸式狀態欄效果

僅僅有android4.4以及以上的版本號才支持狀態欄沉浸效果 先把程序執行在4.4下面的手機上,看下效果: 在4.4以上的效果: 當然圖片也是能夠作為背景的.效果: 代碼: if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {Window window getWindow();window.setFlags(Wind…

為abp vnext生成C#客戶端給非abp第三方net程序使用

abp vnext提供了動態C#API客戶端和靜態C#API客戶端來調用abp項目的接口&#xff0c;但是有局限性&#xff1b;要使用動態C#API客戶端的項目必須也是ABP vnext的項目。靜態C#API客戶端也依賴abp的包&#xff0c;如下圖為的靜態客戶端依賴于 Volo.Abp.DependencyInjection、Volo.…

項目中引入composer包

假如在云服務器上&#xff0c;項目根目錄在 /data/shop&#xff0c;則 示例&#xff1a; cd /data/shop響應的結果可能會有兩種: 1、第一種是直接require成功 示例&#xff1a; composer require haveyb/tiny-laravel #響應結果 ./composer.json has been created Loading …