08-Redis事務講解

1. 概述:

和眾多其它數(shù)據(jù)庫一樣球涛,Redis作為NoSQL數(shù)據(jù)庫也同樣提供了事務機制。在Redis中,MULTI/EXEC/DISCARD/WATCH這四個命令是我們實現(xiàn)事務的基石褥紫。
Redis中事務的實現(xiàn)特征:
 1). 在事務中的所有命令都將會被串行化的順序執(zhí)行事務執(zhí)行期間瞪慧,Redis不會再為其它客戶端的請求提供任何服務髓考,從而保證了事物中的所有命令被原子的執(zhí)行
 2). 和關(guān)系型數(shù)據(jù)庫中的事務相比弃酌,在Redis事務中如果有某一條命令執(zhí)行失敗氨菇,其后的命令仍然會被繼續(xù)執(zhí)行[但最終事務會執(zhí)行失敗]儡炼。
 3). 我們可以通過MULTI命令開啟一個事務,有關(guān)系型數(shù)據(jù)庫開發(fā)經(jīng)驗的人可以將其理解為"BEGIN TRANSACTION"語句查蓉。在該語句之后執(zhí)行的命令都將被視為事務之內(nèi)的操作乌询,最后我們可以通過執(zhí)行EXEC/DISCARD命令來提交/回滾該事務內(nèi)的所有操作。這兩個Redis命令可被視為等同于關(guān)系型數(shù)據(jù)庫中的COMMIT/ROLLBACK語句豌研。
 4). 在事務開啟之前妹田,如果客戶端與服務器之間出現(xiàn)通訊故障并導致網(wǎng)絡斷開,其后所有待執(zhí)行的語句都將不會被服務器執(zhí)行鹃共。然而如果網(wǎng)絡中斷事件是發(fā)生在客戶端執(zhí)行EXEC命令之后鬼佣,那么該事務中的所有命令都會被服務器執(zhí)行。
 5). 當使用Append-Only模式時霜浴,Redis會通過調(diào)用系統(tǒng)函數(shù)write將該事務內(nèi)的所有寫操作在本次調(diào)用中全部寫入磁盤晶衷。然而如果在寫入的過程中出現(xiàn)系統(tǒng)崩潰,如電源故障導致的宕機阴孟,那么此時也許只有部分數(shù)據(jù)被寫入到磁盤晌纫,而另外一部分數(shù)據(jù)卻已經(jīng)丟失。Redis服務器會在重新啟動時執(zhí)行一系列必要的一致性檢測永丝,一旦發(fā)現(xiàn)類似問題缸匪,就會立即退出并給出相應的錯誤提示。此時类溢,我們就要充分利用Redis工具包中提供的redis-check-aof工具凌蔬,該工具可以幫助我們定位到數(shù)據(jù)不一致的錯誤,并將已經(jīng)寫入的部分數(shù)據(jù)進行回滾闯冷。修復之后我們就可以再次重新啟動Redis服務器了砂心。

2. 命令列表
  • MULTI 用于標記事務的開始,其后執(zhí)行的命令都將被存入命令隊列蛇耀,直到執(zhí)行EXEC時辩诞,這些命令才會被原子的執(zhí)行。 始終返回OK
  • EXEC 執(zhí)行在一個事務內(nèi)命令隊列中的所有命令纺涤,同時將當前連接的狀態(tài)恢復為正常狀態(tài)译暂,即非事務狀態(tài)。如果在事務中執(zhí)行了WATCH命令撩炊,那么只有當WATCH所監(jiān)控的Keys沒有被修改的前提下外永,EXEC命令才能執(zhí)行事務隊列中的所有命令,否則EXEC將放棄當前事務中的所有命令拧咳。 原子性的返回事務中各條命令的返回結(jié)果伯顶。如果在事務中使用了WATCH,一旦事務被放棄,EXEC將返回NULL-multi-bulk回復祭衩。
  • DISCARD 回滾事務隊列中的所有命令灶体,同時再將當前連接的狀態(tài)恢復為正常狀態(tài),即非事務狀態(tài)掐暮。如果WATCH命令被使用蝎抽,該命令將UNWATCH所有的Keys。 始終返回OK路克。
  • WATCH key [key ...] O(1) 在MULTI命令執(zhí)行之前织中,可以指定待監(jiān)控的Keys,然而在執(zhí)行EXEC之前衷戈,如果被監(jiān)控的Keys發(fā)生修改狭吼,EXEC將放棄執(zhí)行該事務隊列中的所有命令[實現(xiàn)了類似于“樂觀鎖”的效果,即CAS(check and set)]殖妇。 始終返回OK刁笙。
  • UNWATCH O(1) 取消當前事務中指定監(jiān)控的Keys,如果執(zhí)行了EXEC或DISCARD命令谦趣,則無需再手工執(zhí)行該命令了疲吸,因為在此之后,事務中所有被監(jiān)控的Keys都將自動取消前鹅。 始終返回OK摘悴。
3. 命令示例:
  1. 事務被正常執(zhí)行:
#在Shell命令行下執(zhí)行Redis的客戶端工具。
/> redis-cli
#在當前連接上啟動一個新的事務舰绘。
redis 127.0.0.1:6379> multi
OK
#執(zhí)行事務中的第一條命令蹂喻,從該命令的返回結(jié)果可以看出,該命令并沒有立即執(zhí)行捂寿,而是存于事務的命令隊列口四。
redis 127.0.0.1:6379> incr t1
QUEUED
#又執(zhí)行一個新的命令,從結(jié)果可以看出秦陋,該命令也被存于事務的命令隊列蔓彩。
redis 127.0.0.1:6379> incr t2
QUEUED
#執(zhí)行事務命令隊列中的所有命令,從結(jié)果可以看出驳概,隊列中命令的結(jié)果得到返回赤嚼。
redis 127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
  1. 事務中存在失敗的命令:
#開啟一個新的事務。
redis 127.0.0.1:6379> multi
OK
#設(shè)置鍵a的值為string類型的3顺又。
redis 127.0.0.1:6379> set a 3
QUEUED
#從鍵a所關(guān)聯(lián)的值的頭部彈出元素更卒,由于該值是字符串類型,而lpop命令僅能用于List類型待榔,因此在執(zhí)行exec命令時逞壁,該命令將會失敗。
redis 127.0.0.1:6379> lpop a
QUEUED
#再次設(shè)置鍵a的值為字符串4锐锣。
redis 127.0.0.1:6379> set a 4
QUEUED
#獲取鍵a的值腌闯,以便確認該值是否被事務中的第二個set命令設(shè)置成功。
redis 127.0.0.1:6379> get a
QUEUED
#從結(jié)果中可以看出雕憔,事務中的第二條命令lpop執(zhí)行失敗姿骏,而其后的set和get命令均執(zhí)行成功,這一點是Redis的事務與關(guān)系型數(shù)據(jù)庫中的事務之間最為重要的差別斤彼。
redis 127.0.0.1:6379> exec
1) OK
2) (error) ERR Operation against a key holding the wrong kind of value
3) OK
4) "4"
  1. 回滾事務:
#為鍵t2設(shè)置一個事務執(zhí)行前的值分瘦。
redis 127.0.0.1:6379> set t2 tt
OK
#開啟一個事務。
redis 127.0.0.1:6379> multi
OK
#在事務內(nèi)為該鍵設(shè)置一個新值琉苇。
redis 127.0.0.1:6379> set t2 ttnew
QUEUED
#放棄事務嘲玫。
redis 127.0.0.1:6379> discard
OK
#查看鍵t2的值,從結(jié)果中可以看出該鍵的值仍為事務開始之前的值并扇。
redis 127.0.0.1:6379> get t2
"tt"
4. WATCH命令和基于CAS的樂觀鎖

在Redis的事務中去团,WATCH命令可用于提供CAS(check-and-set)功能。假設(shè)我們通過WATCH命令在事務執(zhí)行之前監(jiān)控了多個Keys穷蛹,倘若在WATCH之后有任何Key的值發(fā)生了變化土陪,EXEC命令執(zhí)行的事務都將被放棄,同時返回Null multi-bulk應答以通知調(diào)用者事務執(zhí)行失敗肴熏。例如鬼雀,我們再次假設(shè)Redis中并未提供incr命令來完成鍵值的原子性遞增,如果要實現(xiàn)該功能蛙吏,我們只能自行編寫相應的代碼源哩。其偽碼如下:
val = GET mykey
val = val + 1
SET mykey $val
以上代碼只有在單連接的情況下才可以保證執(zhí)行結(jié)果是正確的,因為如果在同一時刻有多個客戶端在同時執(zhí)行該段代碼鸦做,那么就會出現(xiàn)多線程程序中經(jīng)常出現(xiàn)的一種錯誤場景--競態(tài)爭用(race condition)璧疗。比如,客戶端A和B都在同一時刻讀取了mykey的原有值馁龟,假設(shè)該值為10崩侠,此后兩個客戶端又均將該值加一后set回Redis服務器,這樣就會導致mykey的結(jié)果為11坷檩,而不是我們認為的12却音。為了解決類似的問題,我們需要借助WATCH命令的幫助矢炼,見如下代碼:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
和此前代碼不同的是系瓢,新代碼在獲取mykey的值之前先通過WATCH命令監(jiān)控了該鍵,此后又將set命令包圍在事務中句灌,這樣就可以有效的保證每個連接在執(zhí)行EXEC之前夷陋,如果當前連接獲取的mykey的值被其它連接的客戶端修改欠拾,那么當前連接的EXEC命令將執(zhí)行失敗。這樣調(diào)用者在判斷返回值后就可以獲悉val是否被重新設(shè)置成功骗绕。

文章內(nèi)容整理自學習資料和網(wǎng)絡, 侵刪.
點擊查看更多事務命令

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末藐窄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酬土,更是在濱河造成了極大的恐慌荆忍,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撤缴,死亡現(xiàn)場離奇詭異刹枉,居然都是意外死亡,警方通過查閱死者的電腦和手機屈呕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門微宝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虎眨,你說我怎么就攤上這事芥吟。” “怎么了专甩?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵钟鸵,是天一觀的道長。 經(jīng)常有香客問我涤躲,道長棺耍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任种樱,我火速辦了婚禮蒙袍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嫩挤。我一直安慰自己害幅,他們只是感情好,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布岂昭。 她就那樣靜靜地躺著以现,像睡著了一般。 火紅的嫁衣襯著肌膚如雪约啊。 梳的紋絲不亂的頭發(fā)上邑遏,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天,我揣著相機與錄音恰矩,去河邊找鬼记盒。 笑死,一個胖子當著我的面吹牛外傅,可吹牛的內(nèi)容都是我干的纪吮。 我是一名探鬼主播俩檬,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碾盟!你這毒婦竟也來了棚辽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤巷疼,失蹤者是張志新(化名)和其女友劉穎晚胡,沒想到半個月后灵奖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嚼沿,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年瓷患,在試婚紗的時候發(fā)現(xiàn)自己被綠了骡尽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡擅编,死狀恐怖攀细,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情爱态,我是刑警寧澤谭贪,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站锦担,受9級特大地震影響俭识,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洞渔,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一套媚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磁椒,春花似錦堤瘤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至医增,卻和暖如春师郑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背调窍。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工宝冕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邓萨。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓地梨,卻偏偏與公主長得像菊卷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宝剖,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容