Redis數(shù)據(jù)庫(kù)高級(jí)實(shí)用特性:事務(wù)控制 |
發(fā)布時(shí)間: 2012/8/7 18:07:33 |
Redis對(duì)事務(wù)的支持目前還比較簡(jiǎn)單。redis只能保證一個(gè)client發(fā)起的事務(wù)中的命令可以連續(xù)的執(zhí)行,而中間不會(huì)插入其他client的命令。 由于redis是單線(xiàn)程來(lái)處理所有client的請(qǐng)求的所以做到這點(diǎn)是很容易的。一般情況下redis在接受到一個(gè)client發(fā)來(lái)的命令后會(huì)立即處理并 返回處理結(jié)果,但是當(dāng)一個(gè)client在一個(gè)連接中發(fā)出multi命令有,這個(gè)連接會(huì)進(jìn)入一個(gè)事務(wù)上下文,該連接后續(xù)的命令并不是立即執(zhí)行,而是先放到一個(gè)隊(duì)列中。當(dāng)從此連接受到exec命令后,redis會(huì)順序的執(zhí)行隊(duì)列中的所有命令。并將所有命令的運(yùn)行結(jié)果打包到一起返回給client.然后此連接就 結(jié)束事務(wù)上下文。 1、簡(jiǎn)單事務(wù)控制 下面可以看一個(gè)例子:
從這個(gè)例子我們可以看到2個(gè)set age命令發(fā)出后并沒(méi)執(zhí)行而是被放到了隊(duì)列中。調(diào)用exec后2個(gè)命令才被連續(xù)的執(zhí)行,最后返回的是兩條命令執(zhí)行后的結(jié)果。 2、如何取消一個(gè)事務(wù) 我們可以調(diào)用discard命令來(lái)取消一個(gè)事務(wù),讓事務(wù)回滾。接著上面例子:
可以發(fā)現(xiàn)這次2個(gè)set age命令都沒(méi)被執(zhí)行。discard命令其實(shí)就是清空事務(wù)的命令隊(duì)列并退出事務(wù)上下文,也就是我們常說(shuō)的事務(wù)回滾。 3、樂(lè)觀鎖復(fù)雜事務(wù)控制 在本小節(jié)開(kāi)始前,我們有必要向讀者朋友簡(jiǎn)單介紹一下樂(lè)觀鎖的概念,并舉例說(shuō)明樂(lè)觀鎖是怎么工作的。 樂(lè)觀鎖:大多數(shù)是基于數(shù)據(jù)版本(version)的記錄機(jī)制實(shí)現(xiàn)的。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識(shí),在基于數(shù)據(jù)庫(kù)表的版本解決方案中,一般是通過(guò)為數(shù)據(jù)庫(kù)表添加一個(gè) “version”字段來(lái)實(shí)現(xiàn)讀取出數(shù)據(jù)時(shí),將此版本號(hào)一同讀出,之后更新時(shí),對(duì)此版本號(hào)加1。 此時(shí),將提交數(shù)據(jù)的版本號(hào)與數(shù)據(jù)庫(kù)表對(duì)應(yīng)記錄的當(dāng)前版本號(hào)進(jìn)行比對(duì),如果提交的數(shù)據(jù)版本號(hào)大于數(shù)據(jù)庫(kù)表當(dāng)前版本號(hào),則予以更新,否則認(rèn)為是過(guò)期數(shù)據(jù)。 樂(lè)觀鎖實(shí)例:假設(shè)數(shù)據(jù)庫(kù)中帳戶(hù)信息表中有一個(gè)version字段,當(dāng)前值為1;而當(dāng)前帳戶(hù)余額字段(balance)為$100。下面我們將用時(shí)序表的方式來(lái)為大家演示樂(lè)觀鎖的實(shí)現(xiàn)原理:
這樣,就避免了操作員B用基于version=1的舊數(shù)據(jù)修改的結(jié)果來(lái)覆蓋操作員A的操作結(jié)果的可能。 即然樂(lè)觀鎖比悲觀鎖要好很多,redis是否也支持呢?答案是支持, redis從2.1.0開(kāi)始就支持樂(lè)觀鎖了,可以顯式的使用watch對(duì)某個(gè)key進(jìn)行加鎖,避免悲觀鎖帶來(lái)的一系列問(wèn)題。 Redis樂(lè)觀鎖實(shí)例: 假設(shè)有一個(gè)age的key,我們開(kāi)2個(gè)session來(lái)對(duì)age進(jìn)行賦值操作,我們來(lái)看一下結(jié)果如何。
從以上實(shí)例可以看到在 第一步,Session 1 還沒(méi)有來(lái)得及對(duì)age的值進(jìn)行修改 第二步,Session 2 已經(jīng)將age的值設(shè)為30 第三步,Session 1 希望將age的值設(shè)為20,但結(jié)果一執(zhí)行返回是nil,說(shuō)明執(zhí)行失敗,之后我們?cè)偃∫幌耡ge的值是30,這是由于Session 1中對(duì)age加了樂(lè)觀鎖導(dǎo)致的。 watch命令會(huì)監(jiān)視給定的key,當(dāng)exec時(shí)候如果監(jiān)視的key從調(diào)用watch后發(fā)生過(guò)變化,則整個(gè)事務(wù)會(huì)失敗。也可以調(diào)用watch多次監(jiān)視多個(gè)key.這 樣就可以對(duì)指定的key加樂(lè)觀鎖了。注意watch的key是對(duì)整個(gè)連接有效的,事務(wù)也一樣。如果連接斷開(kāi),監(jiān)視和事務(wù)都會(huì)被自動(dòng)清除。當(dāng)然了exec,discard,unwatch命令都會(huì)清除連接中的所有監(jiān)視。 redis的事務(wù)實(shí)現(xiàn)是如此簡(jiǎn)單,當(dāng)然會(huì)存在一些問(wèn)題。第一個(gè)問(wèn)題是redis只能保證事務(wù)的每個(gè)命令連續(xù)執(zhí)行,但是如果事務(wù)中的一個(gè)命令失敗了,并不回滾其他命令,比如使用的命令類(lèi)型不匹配。下面將以一個(gè)實(shí)例的例子來(lái)說(shuō)明這個(gè)問(wèn)題:
從這個(gè)例子中可以看到,age由于是個(gè)數(shù)字,那么它可以有自增運(yùn)算,但是name是個(gè)字符串,無(wú)法對(duì)其進(jìn)行自增運(yùn)算,所以會(huì)報(bào)錯(cuò),如果按傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)的思路來(lái)講,整個(gè)事務(wù)都會(huì)回滾,但是我們看到redis卻是將可以執(zhí)行的命令提交了,所以這個(gè)現(xiàn)象對(duì)于習(xí)慣于關(guān)系型數(shù)據(jù)庫(kù)操作的朋友來(lái)說(shuō)是很別扭的,這一點(diǎn)也是redis今天需要改進(jìn)的地方。 本文出自:億恩科技【www.cmtents.com】 服務(wù)器租用/服務(wù)器托管中國(guó)五強(qiáng)!虛擬主機(jī)域名注冊(cè)頂級(jí)提供商!15年品質(zhì)保障!--億恩科技[ENKJ.COM] |