Redis-事物

Redis 通過 MULTI 屏鳍、 DISCARD 锈锤、 EXECWATCH 四個(gè)命令來實(shí)現(xiàn)事務(wù)功能闯割, 本章首先討論使用 MULTI 拉讯、 DISCARDEXEC 三個(gè)命令實(shí)現(xiàn)的一般事務(wù), 然后再來討論帶有 WATCH 的事務(wù)的實(shí)現(xiàn)挑辆。
因?yàn)槭聞?wù)的安全性也非常重要例朱, 所以本章最后通過常見的 ACID 性質(zhì)對 Redis 事務(wù)的安全性進(jìn)行了說明。

事物

事務(wù)提供了一種“將多個(gè)命令打包鱼蝉, 然后一次性洒嗤、按順序地執(zhí)行”的機(jī)制, 并且事務(wù)在執(zhí)行的期間不會主動中斷 —— 服務(wù)器在執(zhí)行完事務(wù)中的所有命令之后魁亦, 才會繼續(xù)處理其他客戶端的其他命令渔隶。
以下是一個(gè)事務(wù)的例子, 它先以 MULTI 開始一個(gè)事務(wù)洁奈, 然后將多個(gè)命令入隊(duì)到事務(wù)中间唉, 最后由 EXEC 命令觸發(fā)事務(wù), 一并執(zhí)行事務(wù)中的所有命令:

redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set msg 'hello world'
QUEUED
redis 127.0.0.1:6379> get msg
QUEUED
redis 127.0.0.1:6379> sadd tag 'java' 'c++' 'C#'
QUEUED
redis 127.0.0.1:6379> smembers tag
QUEUED
redis 127.0.0.1:6379> exec
1) OK
2) "hello world"
3) (integer) 3
4) 1) "c++"
   2) "C#"
   3) "java"
redis 127.0.0.1:6379>

一個(gè)事務(wù)從開始到執(zhí)行會經(jīng)歷以下三個(gè)階段:
1.開始事務(wù)利术。
2.命令入隊(duì)呈野。
3.執(zhí)行事務(wù)。
下文將分別介紹事務(wù)的這三個(gè)階段氯哮。

開始事物

MULTI 命令的執(zhí)行標(biāo)記著事務(wù)的開始:

redis 127.0.0.1:6379> multi
OK

這個(gè)命令唯一做的就是际跪, 將客戶端的 REDIS_MULTI 選項(xiàng)打開, 讓客戶端從非事務(wù)狀態(tài)切換到事務(wù)狀態(tài)喉钢。


命令入隊(duì)

當(dāng)客戶端處于非事務(wù)狀態(tài)下時(shí)姆打, 所有發(fā)送給服務(wù)器端的命令都會立即被服務(wù)器執(zhí)行:

redis 127.0.0.1:6379> set msg 'hello world'
OK
redis 127.0.0.1:6379> get msg
"hello world"

但是, 當(dāng)客戶端進(jìn)入事務(wù)狀態(tài)之后肠虽, 服務(wù)器在收到來自客戶端的命令時(shí)幔戏, 不會立即執(zhí)行命令, 而是將這些命令全部放進(jìn)一個(gè)事務(wù)隊(duì)列里税课, 然后返回 QUEUED 闲延, 表示命令已入隊(duì):

redis 127.0.0.1:6379> set msg 'hello world'
QUEUED
redis 127.0.0.1:6379> get msg
QUEUED

以下流程圖展示了這一行為:



事務(wù)隊(duì)列是一個(gè)數(shù)組, 每個(gè)數(shù)組項(xiàng)是都包含三個(gè)屬性:
1.要執(zhí)行的命令(cmd)韩玩。
2.命令的參數(shù)(argv)垒玲。
3.參數(shù)的個(gè)數(shù)(argc)。
舉個(gè)例子找颓, 如果客戶端執(zhí)行以下命令:

redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set msg 'hello world'
QUEUED
redis 127.0.0.1:6379> get msg
QUEUED
redis 127.0.0.1:6379> sadd tag 'java' 'c++' 'C#'
QUEUED
redis 127.0.0.1:6379> smembers tag
QUEUED

那么程序?qū)榭蛻舳藙?chuàng)建以下事務(wù)隊(duì)列:

數(shù)字索引 cmd argv argc
0 set ["msg","hello world"] 2
1 get ["msg"] 1
2 sadd ["tag","java","c++","C#"] 4
3 smembers ["tag"] 1

執(zhí)行事物

前面說到合愈, 當(dāng)客戶端進(jìn)入事務(wù)狀態(tài)之后, 客戶端發(fā)送的命令就會被放進(jìn)事務(wù)隊(duì)列里。
但其實(shí)并不是所有的命令都會被放進(jìn)事務(wù)隊(duì)列佛析, 其中的例外就是 EXEC 益老、 DISCARDMULTIWATCH 這四個(gè)命令 —— 當(dāng)這四個(gè)命令從客戶端發(fā)送到服務(wù)器時(shí)寸莫, 它們會像客戶端處于非事務(wù)狀態(tài)一樣捺萌, 直接被服務(wù)器執(zhí)行:


如果客戶端正處于事務(wù)狀態(tài), 那么當(dāng) EXEC 命令執(zhí)行時(shí)膘茎, 服務(wù)器根據(jù)客戶端所保存的事務(wù)隊(duì)列桃纯, 以先進(jìn)先出(FIFO)的方式執(zhí)行事務(wù)隊(duì)列中的命令: 最先入隊(duì)的命令最先執(zhí)行, 而最后入隊(duì)的命令最后執(zhí)行披坏。
比如說慈参,對于以下事務(wù)隊(duì)列:

數(shù)字索引 cmd argv argc
0 set ["msg","hello world"] 2
1 get ["msg"] 1
2 sadd ["tag","java","c++","C#"] 4
3 smembers ["tag"] 1

程序會首先執(zhí)行 SET 命令, 然后執(zhí)行 GET 命令刮萌, 再然后執(zhí)行 SADD 命令, 最后執(zhí)行 SMEMBERS 命令娘扩。
執(zhí)行事務(wù)中的命令所得的結(jié)果會以 FIFO 的順序保存到一個(gè)回復(fù)隊(duì)列中着茸。
比如說,對于上面給出的事務(wù)隊(duì)列琐旁,程序?qū)殛?duì)列中的命令創(chuàng)建如下回復(fù)隊(duì)列:

數(shù)字索引 回復(fù)類型 回復(fù)內(nèi)容
0 status code reply OK
1 bulk reply "hello world"
2 integer reply 3
3 multi-bulk reply ["java","c++","C#"]

當(dāng)事務(wù)隊(duì)列里的所有命令被執(zhí)行完之后涮阔, EXEC 命令會將回復(fù)隊(duì)列作為自己的執(zhí)行結(jié)果返回給客戶端, 客戶端從事務(wù)狀態(tài)返回到非事務(wù)狀態(tài)灰殴, 至此敬特, 事務(wù)執(zhí)行完畢。
事務(wù)的整個(gè)執(zhí)行過程可以用以下偽代碼表示:

def execute_transaction():

    # 創(chuàng)建空白的回復(fù)隊(duì)列
    reply_queue = []

    # 取出事務(wù)隊(duì)列里的所有命令牺陶、參數(shù)和參數(shù)數(shù)量
    for cmd, argv, argc in client.transaction_queue:

        # 執(zhí)行命令伟阔,并取得命令的返回值
        reply = execute_redis_command(cmd, argv, argc)

        # 將返回值追加到回復(fù)隊(duì)列末尾
        reply_queue.append(reply)

    # 清除客戶端的事務(wù)狀態(tài)
    clear_transaction_state(client)

    # 清空事務(wù)隊(duì)列
    clear_transaction_queue(client)

    # 將事務(wù)的執(zhí)行結(jié)果返回給客戶端
    send_reply_to_client(client, reply_queue)

在事務(wù)和非事務(wù)狀態(tài)下執(zhí)行命令

無論在事務(wù)狀態(tài)下, 還是在非事務(wù)狀態(tài)下掰伸, Redis 命令都由同一個(gè)函數(shù)執(zhí)行皱炉, 所以它們共享很多服務(wù)器的一般設(shè)置, 比如 AOF 的配置狮鸭、RDB 的配置合搅,以及內(nèi)存限制,等等歧蕉。
不過事務(wù)中的命令和普通命令在執(zhí)行上還是有一點(diǎn)區(qū)別的灾部,其中最重要的兩點(diǎn)是:
1.非事務(wù)狀態(tài)下的命令以單個(gè)命令為單位執(zhí)行,前一個(gè)命令和后一個(gè)命令的客戶端不一定是同一個(gè)惯退;
而事務(wù)狀態(tài)則是以一個(gè)事務(wù)為單位赌髓,執(zhí)行事務(wù)隊(duì)列中的所有命令:除非當(dāng)前事務(wù)執(zhí)行完畢,否則服務(wù)器不會中斷事務(wù),也不會執(zhí)行其他客戶端的其他命令春弥。

2.在非事務(wù)狀態(tài)下呛哟,執(zhí)行命令所得的結(jié)果會立即被返回給客戶端;
而事務(wù)則是將所有命令的結(jié)果集合到回復(fù)隊(duì)列匿沛,再作為 EXEC 命令的結(jié)果返回給客戶端扫责。

事務(wù)狀態(tài)下的 DISCARD 、 MULTI 和 WATCH 命令

除了 EXEC 之外逃呼, 服務(wù)器在客戶端處于事務(wù)狀態(tài)時(shí)鳖孤, 不加入到事務(wù)隊(duì)列而直接執(zhí)行的另外三個(gè)命令是 DISCARDMULTIWATCH 抡笼。
DISCARD 命令用于取消一個(gè)事務(wù)苏揣, 它清空客戶端的整個(gè)事務(wù)隊(duì)列, 然后將客戶端從事務(wù)狀態(tài)調(diào)整回非事務(wù)狀態(tài)推姻, 最后返回字符串 OK
給客戶端平匈, 說明事務(wù)已被取消。
Redis 的事務(wù)是不可嵌套的藏古, 當(dāng)客戶端已經(jīng)處于事務(wù)狀態(tài)增炭, 而客戶端又再向服務(wù)器發(fā)送 MULTI 時(shí), 服務(wù)器只是簡單地向客戶端發(fā)送一個(gè)錯(cuò)誤拧晕, 然后繼續(xù)等待其他命令的入隊(duì)隙姿。 MULTI 命令的發(fā)送不會造成整個(gè)事務(wù)失敗, 也不會修改事務(wù)隊(duì)列中已有的數(shù)據(jù)厂捞。
WATCH 只能在客戶端進(jìn)入事務(wù)狀態(tài)之前執(zhí)行输玷, 在事務(wù)狀態(tài)下發(fā)送 WATCH 命令會引發(fā)一個(gè)錯(cuò)誤, 但它不會造成整個(gè)事務(wù)失敗靡馁, 也不會修改事務(wù)隊(duì)列中已有的數(shù)據(jù)(和前面處理 MULTI 的情況一樣)欲鹏。

帶 WATCH 的事務(wù)

WATCH 命令用于在事務(wù)開始之前監(jiān)視任意數(shù)量的鍵: 當(dāng)調(diào)用 EXEC 命令執(zhí)行事務(wù)時(shí), 如果任意一個(gè)被監(jiān)視的鍵已經(jīng)被其他客戶端修改了奈嘿, 那么整個(gè)事務(wù)不再執(zhí)行貌虾, 直接返回失敗。
以下示例展示了一個(gè)執(zhí)行失敗的事務(wù)例子:

redis 127.0.0.1:6379> watch name
OK
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set name 'cheng'
QUEUED
redis 127.0.0.1:6379> exec
(nil)
redis 127.0.0.1:6379>

以下執(zhí)行序列展示了上面的例子是如何失敗的:

時(shí)間 客戶端A 客戶端B
t1 watch name
t2 multi
t3 set name 'cheng'
t4 set name 'zhao'
t5 exec

在時(shí)間 T4 裙犹,客戶端 B 修改了 name 鍵的值尽狠, 當(dāng)客戶端 A 在 T5 執(zhí)行 EXEC 時(shí),Redis 會發(fā)現(xiàn) name 這個(gè)被監(jiān)視的鍵已經(jīng)被修改叶圃, 因此客戶端 A 的事務(wù)不會被執(zhí)行袄膏,而是直接返回失敗。
下文就來介紹 WATCH 的實(shí)現(xiàn)機(jī)制掺冠,并且看看事務(wù)系統(tǒng)是如何檢查某個(gè)被監(jiān)視的鍵是否被修改沉馆,從而保證事務(wù)的安全性的码党。

WATCH 命令的實(shí)現(xiàn)

在每個(gè)代表數(shù)據(jù)庫的 redis.h/redisDb 結(jié)構(gòu)類型中, 都保存了一個(gè) watched_keys 字典斥黑, 字典的鍵是這個(gè)數(shù)據(jù)庫被監(jiān)視的鍵揖盘, 而字典的值則是一個(gè)鏈表, 鏈表中保存了所有監(jiān)視這個(gè)鍵的客戶端锌奴。
比如說兽狭,以下字典就展示了一個(gè) watched_keys 字典的例子:


其中, 鍵 key1 正在被 client2 鹿蜀、 client5 和 client1 三個(gè)客戶端監(jiān)視箕慧, 其他一些鍵也分別被其他別的客戶端監(jiān)視著。
WATCH 命令的作用茴恰, 就是將當(dāng)前客戶端和要監(jiān)視的鍵在 watched_keys 中進(jìn)行關(guān)聯(lián)颠焦。
舉個(gè)例子, 如果當(dāng)前客戶端為 client10086 往枣, 那么當(dāng)客戶端執(zhí)行 WATCH key1 key2 時(shí)伐庭, 前面展示的 watched_keys 將被修改成這個(gè)樣子:


通過 watched_keys 字典, 如果程序想檢查某個(gè)鍵是否被監(jiān)視分冈, 那么它只要檢查字典中是否存在這個(gè)鍵即可似忧; 如果程序要獲取監(jiān)視某個(gè)鍵的所有客戶端, 那么只要取出鍵的值(一個(gè)鏈表)丈秩, 然后對鏈表進(jìn)行遍歷即可。

WATCH 的觸發(fā)

在任何對數(shù)據(jù)庫鍵空間(key space)進(jìn)行修改的命令成功執(zhí)行之后 (比如 FLUSHDB 淳衙、 SET 蘑秽、 DELLPUSH 箫攀、 SADD 肠牲、 ZREM ,諸如此類)靴跛, multi.c/touchWatchedKey函數(shù)都會被調(diào)用 —— 它檢查數(shù)據(jù)庫的 watched_keys 字典缀雳, 看是否有客戶端在監(jiān)視已經(jīng)被命令修改的鍵, 如果有的話梢睛, 程序?qū)⑺斜O(jiān)視這個(gè)/這些被修改鍵的客戶端的 REDIS_DIRTY_CAS
選項(xiàng)打開:


當(dāng)客戶端發(fā)送 EXEC 命令肥印、觸發(fā)事務(wù)執(zhí)行時(shí), 服務(wù)器會對客戶端的狀態(tài)進(jìn)行檢查:

  • 如果客戶端的 REDIS_DIRTY_CAS 選項(xiàng)已經(jīng)被打開绝葡,那么說明被客戶端監(jiān)視的鍵至少有一個(gè)已經(jīng)被修改了深碱,事務(wù)的安全性已經(jīng)被破壞。服務(wù)器會放棄執(zhí)行這個(gè)事務(wù)藏畅,直接向客戶端返回空回復(fù)敷硅,表示事務(wù)執(zhí)行失敗。
  • 如果 REDIS_DIRTY_CAS 選項(xiàng)沒有被打開,那么說明所有監(jiān)視鍵都安全绞蹦,服務(wù)器正式執(zhí)行事務(wù)力奋。
    可以用一段偽代碼來表示這個(gè)檢查:
def check_safety_before_execute_trasaction():

    if client.state & REDIS_DIRTY_CAS:
        # 安全性已破壞,清除事務(wù)狀態(tài)
        clear_transaction_state(client)
        # 清空事務(wù)隊(duì)列
        clear_transaction_queue(client)
        # 返回空回復(fù)給客戶端
        send_empty_reply(client)
    else:
        # 安全性完好幽七,執(zhí)行事務(wù)
        execute_transaction()

舉個(gè)例子景殷,假設(shè)數(shù)據(jù)庫的 watched_keys 字典如下圖所示:


如果某個(gè)客戶端對 key1 進(jìn)行了修改(比如執(zhí)行 DEL key1 ), 那么所有監(jiān)視 key1 的客戶端锉走, 包括 client2 滨彻、 client5 和 client1 的 REDIS_DIRTY_CAS 選項(xiàng)都會被打開, 當(dāng)客戶端 client2 挪蹭、 client5 和 client1 執(zhí)行 EXEC 的時(shí)候亭饵, 它們的事務(wù)都會以失敗告終。
最后梁厉,當(dāng)一個(gè)客戶端結(jié)束它的事務(wù)時(shí)辜羊,無論事務(wù)是成功執(zhí)行,還是失敗词顾, watched_keys 字典中和這個(gè)客戶端相關(guān)的資料都會被清除八秃。

事務(wù)的 ACID 性質(zhì)

在傳統(tǒng)的關(guān)系式數(shù)據(jù)庫中,常常用 ACID 性質(zhì)來檢驗(yàn)事務(wù)功能的安全性肉盹。
Redis 事務(wù)保證了其中的一致性(C)和隔離性(I)昔驱,但并不保證原子性(A)和持久性(D)。
以下四小節(jié)是關(guān)于這四個(gè)性質(zhì)的詳細(xì)討論上忍。

原子性(Atomicity)

單個(gè) Redis 命令的執(zhí)行是原子性的骤肛,但 Redis 沒有在事務(wù)上增加任何維持原子性的機(jī)制,所以 Redis 事務(wù)的執(zhí)行并不是原子性的窍蓝。如果一個(gè)事務(wù)隊(duì)列中的所有命令都被成功地執(zhí)行腋颠,那么稱這個(gè)事務(wù)執(zhí)行成功。
另一方面吓笙,如果 Redis 服務(wù)器進(jìn)程在執(zhí)行事務(wù)的過程中被停止 —— 比如接到 KILL 信號淑玫、宿主機(jī)器停機(jī),等等面睛,那么事務(wù)執(zhí)行失敗絮蒿。當(dāng)事務(wù)失敗時(shí),Redis 也不會進(jìn)行任何的重試或者回滾動作叁鉴。

一致性(Consistency)

Redis 的一致性問題可以分為三部分來討論:入隊(duì)錯(cuò)誤歌径、執(zhí)行錯(cuò)誤、Redis 進(jìn)程被終結(jié)亲茅。

入隊(duì)錯(cuò)誤

在命令入隊(duì)的過程中回铛,如果客戶端向服務(wù)器發(fā)送了錯(cuò)誤的命令狗准,比如命令的參數(shù)數(shù)量不對,等等茵肃, 那么服務(wù)器將向客戶端返回一個(gè)出錯(cuò)信息腔长, 并且將客戶端的事務(wù)狀態(tài)設(shè)為 REDIS_DIRTY_EXEC 。
當(dāng)客戶端執(zhí)行 EXEC 命令時(shí)验残, Redis 會拒絕執(zhí)行狀態(tài)為 REDIS_DIRTY_EXEC的事務(wù)捞附, 并返回失敗信息。

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> set key
(error) ERR wrong number of arguments for 'set' command
redis 127.0.0.1:6379> EXISTS key
QUEUED
redis 127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

因此您没,帶有不正確入隊(duì)命令的事務(wù)不會被執(zhí)行鸟召,也不會影響數(shù)據(jù)庫的一致性。

執(zhí)行錯(cuò)誤

如果命令在事務(wù)執(zhí)行的過程中發(fā)生錯(cuò)誤氨鹏,比如說欧募,對一個(gè)不同類型的 key 執(zhí)行了錯(cuò)誤的操作, 那么 Redis 只會將錯(cuò)誤包含在事務(wù)的結(jié)果中仆抵, 這不會引起事務(wù)中斷或整個(gè)失敗跟继,不會影響已執(zhí)行事務(wù)命令的結(jié)果,也不會影響后面要執(zhí)行的事務(wù)命令镣丑, 所以它對事務(wù)的一致性也沒有影響舔糖。

Redis 進(jìn)程被終結(jié)

如果 Redis 服務(wù)器進(jìn)程在執(zhí)行事務(wù)的過程中被其他進(jìn)程終結(jié),或者被管理員強(qiáng)制殺死莺匠,那么根據(jù) Redis 所使用的持久化模式金吗,可能有以下情況出現(xiàn):

  • 內(nèi)存模式:如果 Redis 沒有采取任何持久化機(jī)制,那么重啟之后的數(shù)據(jù)庫總是空白的趣竣,所以數(shù)據(jù)總是一致的辽聊。
  • RDB 模式:在執(zhí)行事務(wù)時(shí),Redis 不會中斷事務(wù)去執(zhí)行保存 RDB 的工作期贫,只有在事務(wù)執(zhí)行之后,保存 RDB 的工作才有可能開始异袄。所以當(dāng) RDB 模式下的 Redis 服務(wù)器進(jìn)程在事務(wù)中途被殺死時(shí)通砍,事務(wù)內(nèi)執(zhí)行的命令,不管成功了多少烤蜕,都不會被保存到 RDB 文件里封孙。恢復(fù)數(shù)據(jù)庫需要使用現(xiàn)有的 RDB 文件讽营,而這個(gè) RDB 文件的數(shù)據(jù)保存的是最近一次的數(shù)據(jù)庫快照(snapshot)虎忌,所以它的數(shù)據(jù)可能不是最新的,但只要 RDB 文件本身沒有因?yàn)槠渌麊栴}而出錯(cuò)橱鹏,那么還原后的數(shù)據(jù)庫就是一致的膜蠢。
  • AOF 模式:因?yàn)楸4?AOF 文件的工作在后臺線程進(jìn)行堪藐,所以即使是在事務(wù)執(zhí)行的中途,保存 AOF 文件的工作也可以繼續(xù)進(jìn)行挑围,因此礁竞,根據(jù)事務(wù)語句是否被寫入并保存到 AOF 文件,有以下兩種情況發(fā)生:
    1)如果事務(wù)語句未寫入到 AOF 文件杉辙,或 AOF 未被 SYNC 調(diào)用保存到磁盤模捂,那么當(dāng)進(jìn)程被殺死之后,Redis 可以根據(jù)最近一次成功保存到磁盤的 AOF 文件來還原數(shù)據(jù)庫蜘矢,只要 AOF 文件本身沒有因?yàn)槠渌麊栴}而出錯(cuò)狂男,那么還原后的數(shù)據(jù)庫總是一致的,但其中的數(shù)據(jù)不一定是最新的品腹。
    2)如果事務(wù)的部分語句被寫入到 AOF 文件岖食,并且 AOF 文件被成功保存,那么不完整的事務(wù)執(zhí)行信息就會遺留在 AOF 文件里珍昨,當(dāng)重啟 Redis 時(shí)县耽,程序會檢測到 AOF 文件并不完整,Redis 會退出镣典,并報(bào)告錯(cuò)誤兔毙。需要使用 redis-check-aof 工具將部分成功的事務(wù)命令移除之后,才能再次啟動服務(wù)器兄春。還原之后的數(shù)據(jù)總是一致的澎剥,而且數(shù)據(jù)也是最新的(直到事務(wù)執(zhí)行之前為止)。

隔離性(Isolation)

Redis 是單進(jìn)程程序赶舆,并且它保證在執(zhí)行事務(wù)時(shí)哑姚,不會對事務(wù)進(jìn)行中斷,事務(wù)可以運(yùn)行直到執(zhí)行完所有事務(wù)隊(duì)列中的命令為止芜茵。因此叙量,Redis 的事務(wù)是總是帶有隔離性的。

持久性(Durability)

因?yàn)槭聞?wù)不過是用隊(duì)列包裹起了一組 Redis 命令九串,并沒有提供任何額外的持久性功能绞佩,所以事務(wù)的持久性由 Redis 所使用的持久化模式?jīng)Q定:

  • 在單純的內(nèi)存模式下,事務(wù)肯定是不持久的猪钮。
  • 在 RDB 模式下品山,服務(wù)器可能在事務(wù)執(zhí)行之后、RDB 文件更新之前的這段時(shí)間失敗烤低,所以 RDB 模式下的 Redis 事務(wù)也是不持久的肘交。
  • 在 AOF 的“總是 SYNC ”模式下,事務(wù)的每條命令在執(zhí)行成功之后扑馁,都會立即調(diào)用 fsync 或 fdatasync 將事務(wù)數(shù)據(jù)寫入到 AOF 文件涯呻。但是凉驻,這種保存是由后臺線程進(jìn)行的,主線程不會阻塞直到保存成功魄懂,所以從命令執(zhí)行成功到數(shù)據(jù)保存到硬盤之間沿侈,還是有一段非常小的間隔,所以這種模式下的事務(wù)也是不持久的市栗。
    其他 AOF 模式也和“總是 SYNC ”模式類似缀拭,所以它們都是不持久的。

總結(jié)

  • 事務(wù)提供了一種將多個(gè)命令打包填帽,然后一次性蛛淋、有序地執(zhí)行的機(jī)制。
  • 事務(wù)在執(zhí)行過程中不會被中斷篡腌,所有事務(wù)命令執(zhí)行完之后褐荷,事務(wù)才能結(jié)束。
  • 多個(gè)命令會被入隊(duì)到事務(wù)隊(duì)列中嘹悼,然后按先進(jìn)先出(FIFO)的順序執(zhí)行叛甫。
  • 帶 WATCH 命令的事務(wù)會將客戶端和被監(jiān)視的鍵在數(shù)據(jù)庫的 watched_keys 字典中進(jìn)行關(guān)聯(lián),當(dāng)鍵被修改時(shí)杨伙,程序會將所有監(jiān)視被修改鍵的客戶端的 REDIS_DIRTY_CAS 選項(xiàng)打開其监。
  • 只有在客戶端的 REDIS_DIRTY_CAS 選項(xiàng)未被打開時(shí),才能執(zhí)行事務(wù)限匣,否則事務(wù)直接返回失敗抖苦。
  • Redis 的事務(wù)保證了 ACID 中的一致性(C)和隔離性(I),但并不保證原子性(A)和持久性(D)米死。

轉(zhuǎn)載自http://redisbook.readthedocs.io/en/latest/feature/transaction.html#id11

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锌历,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子峦筒,更是在濱河造成了極大的恐慌究西,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件物喷,死亡現(xiàn)場離奇詭異卤材,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)脯丝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伏伐,“玉大人宠进,你說我怎么就攤上這事∶牯幔” “怎么了材蹬?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵实幕,是天一觀的道長。 經(jīng)常有香客問我堤器,道長昆庇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任闸溃,我火速辦了婚禮整吆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辉川。我一直安慰自己表蝙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布乓旗。 她就那樣靜靜地躺著府蛇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屿愚。 梳的紋絲不亂的頭發(fā)上汇跨,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音妆距,去河邊找鬼穷遂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛毅厚,可吹牛的內(nèi)容都是我干的塞颁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼吸耿,長吁一口氣:“原來是場噩夢啊……” “哼祠锣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咽安,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤伴网,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后妆棒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澡腾,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年糕珊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了动分。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡红选,死狀恐怖澜公,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喇肋,我是刑警寧澤坟乾,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布迹辐,位于F島的核電站,受9級特大地震影響甚侣,放射性物質(zhì)發(fā)生泄漏明吩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一殷费、第九天 我趴在偏房一處隱蔽的房頂上張望印荔。 院中可真熱鬧,春花似錦宗兼、人聲如沸躏鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽染苛。三九已至,卻和暖如春主到,著一層夾襖步出監(jiān)牢的瞬間茶行,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工登钥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留畔师,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓牧牢,卻偏偏與公主長得像看锉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子塔鳍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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

  • redis事務(wù) Redis 通過 MULTI 伯铣、 DISCARD 、 EXEC 和 WATCH 四個(gè)命令來實(shí)現(xiàn)事務(wù)...
    全能程序猿閱讀 2,154評論 0 11
  • 本文摘抄至大鵬的redis教程 redis是一種kv存儲系統(tǒng)轮纫,value支持五種數(shù)據(jù)類型: 字符串(strings...
    lintong閱讀 64,406評論 0 7
  • 本文將從Redis的基本特性入手掌唾,通過講述Redis的數(shù)據(jù)結(jié)構(gòu)和主要命令對Redis的基本能力進(jìn)行直觀介紹放前。之后概...
    kelgon閱讀 61,122評論 24 626
  • java語言概述 1、java8的新特性糯彬。 重新設(shè)計(jì)的接口語法凭语,Lambda表達(dá)式,方法引用撩扒,構(gòu)造器引用似扔,函數(shù)式編...
    ifeelok0319閱讀 197評論 0 0
  • 我喜歡一個(gè)人靜靜的喜歡你,沒有浮躁沒有喧鬧。暗戀虫几,也許比表白更加有能量。感情上其實(shí)不存在誰配不上誰挽拔,感情是純粹...
    紅色小奔馳閱讀 443評論 0 1