Redis 实用技术——事务
引言
redis的事務(wù)不像關(guān)系型數(shù)據(jù)庫的事務(wù)那樣完整。
“快”是redis的特征,在事務(wù)管理的過程中,使用muti命令開啟事務(wù)塊,當(dāng)輸入多條命令后,再使用exec命令執(zhí)行事務(wù)塊中的全部命令。
Redis事務(wù)可以保證兩件事:
1、隔離性:事務(wù)是一個(gè)單獨(dú)的隔離操作,這和關(guān)系型數(shù)據(jù)庫的事務(wù)原則是一致的,事務(wù)中的所有命令都會(huì)順序執(zhí)行,且中途不會(huì)被其他事務(wù)打斷。
2、原子性:要么全部執(zhí)行,要么全不執(zhí)行。
一、查看幫助
MULTI、EXEC、DISCARD、WATCH 是 Redis 事務(wù)的相關(guān)命令:
MULTI 命令用于開啟一個(gè)事務(wù),它總是返回OK,執(zhí)行后,客戶端可以繼續(xù)向服務(wù)器發(fā)送多條命令,這些命令會(huì)被暫時(shí)存放到隊(duì)列中而不執(zhí)行。
EXEC 命令負(fù)責(zé)觸發(fā)并執(zhí)行事務(wù)中的所有命令,如果客戶端在使用 MULTI 開啟一個(gè)事務(wù)之后,因?yàn)榈艟€沒有成功執(zhí)行 EXEC ,那么事務(wù)中的所有命令都不會(huì)被執(zhí)行。
DISCARD 客戶端可以通過這個(gè)命令清空事務(wù)隊(duì)列,視為放棄執(zhí)行事務(wù)。
二、并發(fā)下的事務(wù)
由于Redis是單線程處理全部用戶請(qǐng)求,因此,在并發(fā)事務(wù)中,每個(gè)命令都會(huì)排隊(duì)執(zhí)行,事務(wù)之間很可能出現(xiàn)“先刪后取”的問題。
不論 multi 執(zhí)行的先后,Redis 只根據(jù)最先接收到的?exec 命令來執(zhí)行事務(wù)。
如上圖所示,綠色事務(wù)先開啟事務(wù)塊,但是在執(zhí)行 exec 提交事務(wù)之前,被一個(gè)刪除事務(wù)提前執(zhí)行,那么綠色事務(wù)就無法正確獲取 key 的value。
三、WATCH 提供的 CAS
WATCH 可以讓 exec 命令有條件的執(zhí)行:事務(wù)只能在所有被監(jiān)視的key都沒有被修改的前提下執(zhí)行。這是watch為redis提供的check-and-set(CAS)行為。
watch 命令可以被調(diào)用多次,對(duì) key 的監(jiān)視從 watch 執(zhí)行之后生效,直到調(diào)用 exec 為止。當(dāng)exec 被調(diào)用時(shí),不管事務(wù)是否成功執(zhí)行,對(duì)所有 key 的監(jiān)視都會(huì)被取消。
使用 無參的 unwatch ,可以手動(dòng)取消對(duì)所有 key 的監(jiān)視。
如果有至少一個(gè)被監(jiān)視的 key 在 exec 執(zhí)行之前被修改,那么整個(gè)事務(wù)都會(huì)被取消,exec 返回 nil-reply 來表示事務(wù)已經(jīng)失敗。
上面的兩個(gè)客戶端,左側(cè)先watch stu 監(jiān)視,右側(cè)客戶端更改 stu ,左側(cè)再開啟事務(wù)并修改 stu,最后 exec ,返回結(jié)果為 nil,且stu最終并沒有被改變。
這種形式的鎖被稱為樂觀鎖,它是一種非常強(qiáng)大的鎖機(jī)制,并且因?yàn)榇蠖鄶?shù)情況下,不同的客戶端會(huì)訪問不同的鍵,碰撞的情況一般都很少,所以通常并不需要進(jìn)行重試。
另外,當(dāng)客戶端斷開連接時(shí),該客戶端對(duì) key 的監(jiān)視也會(huì)被取消。
四、事務(wù)中的錯(cuò)誤
使用事務(wù)時(shí)可能會(huì)遇到兩種錯(cuò)誤:
1、執(zhí)行 exec 之前入列命令錯(cuò)誤,如語法、參數(shù)名、參數(shù)數(shù)量等。或其他嚴(yán)重錯(cuò)誤,內(nèi)存不足等。
2、執(zhí)行 exec 之后失敗,例如,事務(wù)中的命令與處理的類型不匹配等等。
對(duì)于第一種錯(cuò)誤,在 Redis 2.6.5 之前,客戶端會(huì)檢查命令入列的返回值,如果是 QUEUED,入列成功,否則入列失敗。
從 2.6.5 開始,服務(wù)器會(huì)對(duì)命令入列失敗的情況進(jìn)行記錄,并在客戶端調(diào)用 exec 命令時(shí),拒絕并自動(dòng)放棄這個(gè)事務(wù)。
這種改進(jìn)方式,是為了在 Redis 管道中包含事務(wù),如果是以前的做法,那么一條拼接的多條命令如果中間某個(gè)出了問題將很難快速有效的執(zhí)行,而改進(jìn)后,情況就變得簡(jiǎn)單,發(fā)送事務(wù)和讀取事務(wù)的回復(fù)都只需要和服務(wù)器進(jìn)行一次通訊。
對(duì)于第二種錯(cuò)誤,exec 執(zhí)行時(shí)或之后出錯(cuò),并沒有什么特別的處理,即使事務(wù)中有某些命令在執(zhí)行時(shí)產(chǎn)生錯(cuò)誤,事務(wù)中的其他命令仍然會(huì)繼續(xù)執(zhí)行。
至于事務(wù)回復(fù)中,有一些是 OK 而有一些是 ERR,就需要由客戶端自己決定如何處理,Redis 不會(huì)停止執(zhí)行事務(wù)中的命令。
這就是 “Redis 在事務(wù)失敗時(shí)不進(jìn)行回滾,而是繼續(xù)執(zhí)行余下的命令”的含義。這樣做有以下幾點(diǎn)優(yōu)點(diǎn):
1、Redis 命令只會(huì)因?yàn)殄e(cuò)誤的語法而失敗(并且這些問題不能在入隊(duì)時(shí)發(fā)現(xiàn)),或是命令用在了錯(cuò)誤類型的鍵上面:這也就是說,從實(shí)用性的角度來說,失敗的命令是由編程錯(cuò)誤造成的,而這些錯(cuò)誤應(yīng)該在開發(fā)的過程中被發(fā)現(xiàn),而不應(yīng)該出現(xiàn)在生產(chǎn)環(huán)境中。
2、因?yàn)椴恍枰獙?duì)回滾進(jìn)行支持,所以 Redis 的內(nèi)部可以保持簡(jiǎn)單且快速。
所以,通常對(duì)于精度要求不是特別嚴(yán)格的場(chǎng)合,就可以使用 redis 事務(wù),而不應(yīng)該將其用在類似銀行轉(zhuǎn)賬的嚴(yán)格的事務(wù)場(chǎng)合。
?
?
?
總結(jié)
以上是生活随笔為你收集整理的Redis 实用技术——事务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring读取properties配置
- 下一篇: mysql 读取properties_J