一、Redis 事務(wù)
Redis 事務(wù)可以一次執(zhí)行多個(gè)命令, 并且?guī)в幸韵聝蓚€(gè)重要的保證:
批量操作在發(fā)送 EXEC 命令前被放入隊(duì)列緩存。
收到 EXEC 命令后進(jìn)入事務(wù)執(zhí)行,事務(wù)中任意命令執(zhí)行失敗,其余的命令依然被執(zhí)行。
在事務(wù)執(zhí)行過(guò)程,其他客戶端提交的命令請(qǐng)求不會(huì)插入到事務(wù)執(zhí)行命令序列中。
一個(gè)事務(wù)從開(kāi)始到執(zhí)行會(huì)經(jīng)歷以下三個(gè)階段:
- 開(kāi)始事務(wù)。
- 命令入隊(duì)。
- 執(zhí)行事務(wù)。
事務(wù)的ACID性質(zhì):
ACID即為原子性(Atomicity),一致性(Consistency),隔離性(Isolation),耐久性(Durability)。
事務(wù)的應(yīng)用
事務(wù)的應(yīng)用非常普遍,如銀行轉(zhuǎn)賬過(guò)程中A給B匯款,首先系統(tǒng)從A的賬戶中將錢劃走,然后向B的賬戶增加相應(yīng)的金額。這兩個(gè)步驟必須屬于同一個(gè)事務(wù),要么全執(zhí)行,要么全不執(zhí)行。否則只執(zhí)行第一步,錢就憑空消失了,這顯然讓人無(wú)法接受。
二、事務(wù)的實(shí)現(xiàn)
事務(wù)開(kāi)始(以MULTI為標(biāo)志) -> 命令入隊(duì)(命令一次進(jìn)入隊(duì)列) -> 事務(wù)執(zhí)行(通過(guò)EXEC執(zhí)行)
- 示例
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
127.0.0.1:6379> GET book-name
QUEUED
127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
127.0.0.1:6379> SMEMBERS tag
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
2) "Programming"
3) "C++"
單個(gè) Redis 命令的執(zhí)行是原子性的,但 Redis 沒(méi)有在事務(wù)上增加任何維持原子性的機(jī)制,所以 Redis 事務(wù)的執(zhí)行并不是原子性的。
事務(wù)可以理解為一個(gè)打包的批量執(zhí)行腳本,但批量指令并非原子化的操作,中間某條指令的失敗不會(huì)導(dǎo)致前面已做指令的回滾,也不會(huì)造成后續(xù)的指令不做。
- 事務(wù)的錯(cuò)誤處理
如果一個(gè)事務(wù)中的某個(gè)命令執(zhí)行出錯(cuò),Redis會(huì)怎樣處理呢?要回答這個(gè)問(wèn)題,首先需要知道什么原因會(huì)導(dǎo)致命令執(zhí)行出錯(cuò)。
- 語(yǔ)法錯(cuò)誤
語(yǔ)法錯(cuò)誤指命令不存在或者命令參數(shù)的個(gè)數(shù)不對(duì)。比如:
redis>MULTI
OK
redis>SET key value
QUEUED
redis>SET key
(error)ERR wrong number of arguments for 'set' command
redis> errorCOMMAND key
(error) ERR unknown command 'errorCOMMAND'
redis> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
跟在MULTI命令后執(zhí)行了3個(gè)命令:一個(gè)是正確的命令,成功地加入事務(wù)隊(duì)列;其余兩個(gè)命令都有語(yǔ)法錯(cuò)誤。而只要有一個(gè)命令有語(yǔ)法錯(cuò)誤,執(zhí)行EXEC命令后Redis就會(huì)直接返回錯(cuò)誤,連語(yǔ)法正確的命令也不會(huì)執(zhí)行。
這里需要注意一點(diǎn):
Redis 2.6.5之前的版本會(huì)忽略有語(yǔ)法錯(cuò)誤的命令,然后執(zhí)行事務(wù)中其他語(yǔ)法正確的命令。就此例而言,SET key value會(huì)被執(zhí)行,EXEC命令會(huì)返回一個(gè)結(jié)果:1) OK。
- 運(yùn)行錯(cuò)誤
運(yùn)行錯(cuò)誤指在命令執(zhí)行時(shí)出現(xiàn)的錯(cuò)誤,比如使用散列類型的命令操作集合類型的鍵,這種錯(cuò)誤在實(shí)際執(zhí)行之前Redis是無(wú)法發(fā)現(xiàn)的,所以在事務(wù)里這樣的命令是會(huì)被Redis接受并執(zhí)行的。如果事務(wù)里的一條命令出現(xiàn)了運(yùn)行錯(cuò)誤,事務(wù)里其他的命令依然會(huì)繼續(xù)執(zhí)行(包括出錯(cuò)命令之后的命令),示例如下:
redis>MULTI
OK
redis>SET key 1
QUEUED
redis>SADD key 2
QUEUED
redis>SET key 3
QUEUED
redis>EXEC
1) OK
2) (error) ERR Operation against a key holding the wrong kind of value
3) OK
redis>GET key
"3"
可見(jiàn)雖然SADD key 2出現(xiàn)了錯(cuò)誤,但是SET key 3依然執(zhí)行了。
Redis的事務(wù)沒(méi)有關(guān)系數(shù)據(jù)庫(kù)事務(wù)提供的回滾(rollback)功能。為此開(kāi)發(fā)者必須在事務(wù)執(zhí)行出錯(cuò)后自己收拾剩下的攤子(將數(shù)據(jù)庫(kù)復(fù)原回事務(wù)執(zhí)行前的狀態(tài)等,這里我們一般采取日志記錄然后業(yè)務(wù)補(bǔ)償?shù)姆绞絹?lái)處理,但是一般情況下,在redis做的操作不應(yīng)該有這種強(qiáng)一致性要求的需求,我們認(rèn)為這種需求為不合理的設(shè)計(jì))。
三、WATCH命令
Redis Watch 命令用于監(jiān)視一個(gè)(或多個(gè)) key ,如果在事務(wù)執(zhí)行之前這個(gè)(或這些) key 被其他命令所改動(dòng),那么事務(wù)將被打斷。
語(yǔ)法
redis Watch 命令基本語(yǔ)法如下:
WATCH key [key ...]
返回值
總是返回 OK 。
127.0.0.1:6379> WATCH lock lock_times
OK
四、Redis 事務(wù)命令
序號(hào) 命令及描述
1 DISCARD
取消事務(wù),放棄執(zhí)行事務(wù)塊內(nèi)的所有命令。
2 EXEC
執(zhí)行所有事務(wù)塊內(nèi)的命令。
3 MULTI
標(biāo)記一個(gè)事務(wù)塊的開(kāi)始。
4 UNWATCH
取消 WATCH 命令對(duì)所有 key 的監(jiān)視。
5 WATCH key [key ...]
監(jiān)視一個(gè)(或多個(gè)) key ,如果在事務(wù)執(zhí)行之前這個(gè)(或這些) key 被其他命令所改動(dòng),那么事務(wù)將被打斷。