Redis的事務(wù)處理

眾所周知,事務(wù)是指“一個(gè)完整的動(dòng)作,要么全部執(zhí)行,要么什么也沒(méi)有做”。

在聊redis事務(wù)處理之前,要先和大家介紹四個(gè)redis指令,即MULTI、EXEC、DISCARD、WATCH。這四個(gè)指令構(gòu)成了redis事務(wù)處理的基礎(chǔ)。

1.MULTI用來(lái)組裝一個(gè)事務(wù);
2.EXEC用來(lái)執(zhí)行一個(gè)事務(wù);
3.DISCARD用來(lái)取消一個(gè)事務(wù);
4.WATCH用來(lái)監(jiān)視一些key,一旦這些key在事務(wù)執(zhí)行之前被改變,則取消事務(wù)的執(zhí)行。

紙上得來(lái)終覺(jué)淺,我們來(lái)看一個(gè)MULTI和EXEC的例子:

redis> MULTI //標(biāo)記事務(wù)開始
OK
redis> INCR user_id //多條命令按順序入隊(duì)
QUEUED
redis> INCR user_id
QUEUED
redis> INCR user_id
QUEUED
redis> PING
QUEUED
redis> EXEC //執(zhí)行
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG

在上面的例子中,我們看到了QUEUED的字樣,這表示我們?cè)谟肕ULTI組裝事務(wù)時(shí),每一個(gè)命令都會(huì)進(jìn)入到內(nèi)存隊(duì)列中緩存起來(lái),如果出現(xiàn)QUEUED則表示我們這個(gè)命令成功插入了緩存隊(duì)列,在將來(lái)執(zhí)行EXEC時(shí),這些被QUEUED的命令都會(huì)被組裝成一個(gè)事務(wù)來(lái)執(zhí)行。

對(duì)于事務(wù)的執(zhí)行來(lái)說(shuō),如果redis開啟了AOF持久化的話,那么一旦事務(wù)被成功執(zhí)行,事務(wù)中的命令就會(huì)通過(guò)write命令一次性寫到磁盤中去,如果在向磁盤中寫的過(guò)程中恰好出現(xiàn)斷電、硬件故障等問(wèn)題,那么就可能出現(xiàn)只有部分命令進(jìn)行了AOF持久化,這時(shí)AOF文件就會(huì)出現(xiàn)不完整的情況,這時(shí),我們可以使用redis-check-aof工具來(lái)修復(fù)這一問(wèn)題,這個(gè)工具會(huì)將AOF文件中不完整的信息移除,確保AOF文件完整可用。

有關(guān)事務(wù),大家經(jīng)常會(huì)遇到的是兩類錯(cuò)誤:

1.調(diào)用EXEC之前的錯(cuò)誤
2.調(diào)用EXEC之后的錯(cuò)誤

“調(diào)用EXEC之前的錯(cuò)誤”,有可能是由于語(yǔ)法有誤導(dǎo)致的,也可能時(shí)由于內(nèi)存不足導(dǎo)致的。只要出現(xiàn)某個(gè)命令無(wú)法成功寫入緩沖隊(duì)列的情況,redis都會(huì)進(jìn)行記錄,在客戶端調(diào)用EXEC時(shí),redis會(huì)拒絕執(zhí)行這一事務(wù)。(這時(shí)2.6.5版本之后的策略。在2.6.5之前的版本中,redis會(huì)忽略那些入隊(duì)失敗的命令,只執(zhí)行那些入隊(duì)成功的命令)。我們來(lái)看一個(gè)這樣的例子:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> haha //一個(gè)明顯錯(cuò)誤的指令
(error) ERR unknown command 'haha'
127.0.0.1:6379> ping
QUEUED
127.0.0.1:6379> exec
//redis無(wú)情的拒絕了事務(wù)的執(zhí)行,原因是“之前出現(xiàn)了錯(cuò)誤”
(error) EXECABORT Transaction discarded because of previous errors.

而對(duì)于“調(diào)用EXEC之后的錯(cuò)誤”,redis則采取了完全不同的策略,即redis不會(huì)理睬這些錯(cuò)誤,而是繼續(xù)向下執(zhí)行事務(wù)中的其他命令。這是因?yàn)?,?duì)于應(yīng)用層面的錯(cuò)誤,并不是redis自身需要考慮和處理的問(wèn)題,所以一個(gè)事務(wù)中如果某一條命令執(zhí)行失敗,并不會(huì)影響接下來(lái)的其他命令的執(zhí)行。我們也來(lái)看一個(gè)例子:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 23
QUEUED
//age不是集合,所以如下是一條明顯錯(cuò)誤的指令
127.0.0.1:6379> sadd age 15 
QUEUED
127.0.0.1:6379> set age 29
QUEUED
127.0.0.1:6379> exec //執(zhí)行事務(wù)時(shí),redis不會(huì)理睬第2條指令執(zhí)行錯(cuò)誤
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get age
"29" //可以看出第3條指令被成功執(zhí)行了

好了,我們來(lái)說(shuō)說(shuō)最后一個(gè)指令“WATCH”,這是一個(gè)很好用的指令,它可以幫我們實(shí)現(xiàn)類似于“樂(lè)觀鎖”的效果,即CAS(check and set)。

WATCH本身的作用是“監(jiān)視key是否被改動(dòng)過(guò)”,而且支持同時(shí)監(jiān)視多個(gè)key,只要還沒(méi)真正觸發(fā)事務(wù),WATCH都會(huì)盡職盡責(zé)的監(jiān)視,一旦發(fā)現(xiàn)某個(gè)key被修改了,在執(zhí)行EXEC時(shí)就會(huì)返回nil,表示事務(wù)無(wú)法觸發(fā)。

127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> watch age //開始監(jiān)視age
OK
127.0.0.1:6379> set age 24 //在EXEC之前,age的值被修改了
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 25
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec //觸發(fā)EXEC
(nil) //事務(wù)無(wú)法被執(zhí)行
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • redis是什么 redis是一個(gè)開源的、使用C語(yǔ)言編寫的、支持網(wǎng)絡(luò)交互的、可基于內(nèi)存也可持久化的Key-Valu...
    燁楓_邱閱讀 834評(píng)論 0 6
  • redis事務(wù) Redis 通過(guò) MULTI 、 DISCARD 、 EXEC 和 WATCH 四個(gè)命令來(lái)實(shí)現(xiàn)事務(wù)...
    全能程序猿閱讀 2,253評(píng)論 0 11
  • 五種數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介 Redis是使用C編寫的,內(nèi)部實(shí)現(xiàn)了一個(gè)struct結(jié)構(gòu)體redisObject對(duì)象,通過(guò)結(jié)構(gòu)體...
    彥幀閱讀 7,167評(píng)論 0 14
  • 本文摘抄至大鵬的redis教程 redis是一種kv存儲(chǔ)系統(tǒng),value支持五種數(shù)據(jù)類型: 字符串(strings...
    lintong閱讀 64,452評(píng)論 0 7
  • Redis 通過(guò) MULTI 、 DISCARD 、 EXEC 和 WATCH 四個(gè)命令來(lái)實(shí)現(xiàn)事務(wù)功能, 本章首先...
    binge1024閱讀 560評(píng)論 0 2

友情鏈接更多精彩內(nèi)容