欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis事務(wù)為什么不支持回滾

 更新時(shí)間:2021年08月10日 09:39:36   作者:雙子孤狼  
事務(wù)是關(guān)系型數(shù)據(jù)庫的特征之一,那么作為 Nosql 的代表 Redis 中有事務(wù)嗎?如果有,那么 Redis 當(dāng)中的事務(wù)又是否具備關(guān)系型數(shù)據(jù)庫的 ACID 四大特性,本文就來詳細(xì)介紹一下

前言

事務(wù)是關(guān)系型數(shù)據(jù)庫的特征之一,那么作為 Nosql 的代表 Redis 中有事務(wù)嗎?如果有,那么 Redis 當(dāng)中的事務(wù)又是否具備關(guān)系型數(shù)據(jù)庫的 ACID 四大特性呢?

Redis 有事務(wù)嗎

這個(gè)答案可能會(huì)令很多人感到意外,Redis 當(dāng)中是存在“事務(wù)”的。這里我把 Redis 的事務(wù)帶了引號,原因在后面分析。

Redis 當(dāng)中的單個(gè)命令都是原子操作,但是如果我們需要把多個(gè)命令組合操作又需要保證數(shù)據(jù)的一致性時(shí),就可以考試使用 Redis 提供的事務(wù)(或者使用前面介紹的 Lua 腳本)。

Redis 當(dāng)中,通過下面 4 個(gè)命令來實(shí)現(xiàn)事務(wù):

  • multi:開啟事務(wù)
  • exec:執(zhí)行事務(wù)
  • discard:取消事務(wù)
  • watch:監(jiān)視

Redis 的事務(wù)主要分為以下 3 步:

  • 執(zhí)行命令 multi 開啟一個(gè)事務(wù)。
  • 開啟事務(wù)之后執(zhí)行的命令都會(huì)被放入一個(gè)隊(duì)列,如果成功之后會(huì)固定返回 QUEUED。
  • 執(zhí)行命令 exec 提交事務(wù)之后,Redis 會(huì)依次執(zhí)行隊(duì)列里面的命令,并依次返回所有命令結(jié)果(如果想要放棄事務(wù),可以執(zhí)行 discard 命令)。

接下來讓我們依次執(zhí)行以下命令來體會(huì)一下 Redis 當(dāng)中的事務(wù):

multi //開啟事務(wù)
set name lonely_wolf //設(shè)置 name,此時(shí) Redis 會(huì)將命令放入隊(duì)列
set age 18  //設(shè)值 age,此時(shí) Redis 會(huì)將命令放入隊(duì)列
get name  //獲取 name,此時(shí) Redis 會(huì)將命令放入隊(duì)列
exec //提交事務(wù),此時(shí)會(huì)依次執(zhí)行隊(duì)列里的命令,并依次返回結(jié)果

執(zhí)行完成之后得到如下效果:

在這里插入圖片描述

Redis 事務(wù)實(shí)現(xiàn)原理

Redis 中每個(gè)客戶端都有記錄當(dāng)前客戶端的事務(wù)狀態(tài) multiState,下面就是一個(gè)客戶端 client 的數(shù)據(jù)結(jié)構(gòu)定義:

typedef struct client {
    uint64_t id;//客戶端唯一 id
    multiState mstate; //MULTI 和 EXEC 狀態(tài)(即事務(wù)狀態(tài))
    //...省略其他屬性
} client;

multiState 數(shù)據(jù)結(jié)構(gòu)定義如下:

typedef struct multiState {
    multiCmd *commands;//存儲命令的 FIFO 隊(duì)列
    int count;//命令總數(shù)
    //...省略了其他屬性
} multiState;

multiCmd 是一個(gè)隊(duì)列,用來接收并存儲開啟事務(wù)之后發(fā)送的命令,其數(shù)據(jù)結(jié)構(gòu)定義如下:

typedef struct multiCmd {
    robj **argv;//用來存儲參數(shù)的數(shù)組
    int argc;//參數(shù)的數(shù)量
    struct redisCommand *cmd;//命令指針
} multiCmd;

我們以上面事務(wù)的示例截圖中事務(wù)為例,可以得到如下所示的一個(gè)簡圖:

在這里插入圖片描述

Redis 事務(wù) ACID 特性

傳統(tǒng)的關(guān)系型數(shù)據(jù)庫中,一個(gè)事務(wù)一般都具有 ACID 特性。那么現(xiàn)在就讓我們來分析一下 Redis 是否也滿足這 ACID 四大特性。

A - 原子性

在討論事務(wù)的原子性之前,我們先來看 2 個(gè)例子。

模擬事務(wù)在執(zhí)行命令前發(fā)生異常。依次執(zhí)行以下命令:

multi //開啟事務(wù)
set name lonely_wolf //設(shè)置 name,此時(shí) Redis 會(huì)將命令放入隊(duì)列
get  //執(zhí)行一個(gè)不完成的命令,此時(shí)會(huì)報(bào)錯(cuò)
exec //在發(fā)生異常后提交事務(wù)

最終得到了如下圖所示的結(jié)果,我們可以看到,當(dāng)命令入隊(duì)的時(shí)候報(bào)錯(cuò)時(shí),事務(wù)已經(jīng)被取消了:

在這里插入圖片描述

模擬事務(wù)在執(zhí)行命令前發(fā)生異常。依次執(zhí)行以下命令:

flushall //為了防止影響,先清空數(shù)據(jù)庫
multi //開啟事務(wù)
set name lonely_wolf //設(shè)置 name,此時(shí) Redis 會(huì)將命令放入隊(duì)列
incr name  //這個(gè)命令只能用于 value 為整數(shù)的字符串對象,此時(shí)執(zhí)行會(huì)報(bào)錯(cuò)
exec //提交事務(wù),此時(shí)在執(zhí)行第一條命令成功,執(zhí)行第二條命令失敗
get name //獲取 name 的值

最終得到了如下圖所示的結(jié)果,我們可以看到,當(dāng)執(zhí)行事務(wù)報(bào)錯(cuò)的時(shí)候,之前已經(jīng)成功的命令并沒有被回滾,也就是說在執(zhí)行事務(wù)的時(shí)候某一個(gè)命令失敗了,并不會(huì)影響其他命令的執(zhí)行,即 Redis 的事務(wù)并不會(huì)回滾

在這里插入圖片描述

Redis 中的事務(wù)為什么不會(huì)滾

這個(gè)問題的答案在 Redis 官網(wǎng)中給出了明確的解釋:

在這里插入圖片描述

總結(jié)起來主要就是 3 個(gè)原因:

  • Redis 作者認(rèn)為發(fā)生事務(wù)回滾的原因大部分都是程序錯(cuò)誤導(dǎo)致,這種情況一般發(fā)生在開發(fā)和測試階段,而生產(chǎn)環(huán)境很少出現(xiàn)。
  • 對于邏輯性錯(cuò)誤,比如本來應(yīng)該把一個(gè)數(shù)加 1 ,但是程序邏輯寫成了加 2,那么這種錯(cuò)誤也是無法通過事務(wù)回滾來進(jìn)行解決的。
  • Redis 追求的是簡單高效,而傳統(tǒng)事務(wù)的實(shí)現(xiàn)相對比較復(fù)雜,這和 Redis 的設(shè)計(jì)思想相違背。

 C - 一致性

一致性指的就是事務(wù)執(zhí)行前后的數(shù)據(jù)符合數(shù)據(jù)庫的定義和要求。這一點(diǎn) Redis 中的事務(wù)是符合要求的,上面講述原子性的時(shí)候已經(jīng)提到,不論是發(fā)生語法錯(cuò)誤還是運(yùn)行時(shí)錯(cuò)誤,錯(cuò)誤的命令均不會(huì)被執(zhí)行。

I - 隔離性

事務(wù)中的所有命令都會(huì)按順序執(zhí)行,在執(zhí)行 Redis 事務(wù)的過程中,另一個(gè)客戶端發(fā)出的請求不可能被服務(wù),這保證了命令是作為單獨(dú)的獨(dú)立操作執(zhí)行的。所以 Redis 當(dāng)中的事務(wù)是符合隔離性要求的。

D - 持久性

如果 Redis 當(dāng)中沒有被開啟持久化,那么就是純內(nèi)存運(yùn)行的,一旦重啟,所有數(shù)據(jù)都會(huì)丟失,此時(shí)可以認(rèn)為 Redis 不具備事務(wù)的持久性;而如果 Redis 開啟了持久化,那么可以認(rèn)為 Redis 在特定條件下是具備持久性的。

watch 命令

上面我們講述 Redis 中事務(wù)時(shí),提到的的常用命令還有一個(gè) watch 命令,這個(gè)又是做什么用的呢?我們還是先來看一個(gè)例子。

首先打開一個(gè)客戶端一,依次執(zhí)行以下命令:

flushall  //清空數(shù)據(jù)庫
multi     //開啟事務(wù)
get name  //獲取 name,此時(shí)正常返回 nil
set name lonely_wolf //設(shè)置 name
get name //獲取 name,此時(shí)正常應(yīng)該返回 lonely_wolf

得到如下效果圖:

在這里插入圖片描述

這時(shí)候我們先不執(zhí)行事務(wù),打開另一個(gè)客戶端二,來執(zhí)行一個(gè)命令 set name zhangsan

在這里插入圖片描述

客戶端二執(zhí)行成功了,這時(shí)候再返回到客戶端一執(zhí)行 exec 命令:

在這里插入圖片描述

可以發(fā)現(xiàn),第一句話返回了 zhangsan。也就是說,name 這個(gè) key 值在入隊(duì)之后到 exec 之前發(fā)生了變化,一旦發(fā)生這種情況,可能會(huì)引起很嚴(yán)重的問題,所以在關(guān)系型數(shù)據(jù)庫可以通過鎖來解決這種問題,那么 Redis 當(dāng)中試如何解決的呢?

是的,在 Redis 當(dāng)中就是通過 watch 命令來處理這種場景的。

watch 命令的作用

watch 命令可以為 Redis 事務(wù)提供 CAS 樂觀鎖行為,它可以在 exec 命令執(zhí)行之前,監(jiān)視任意 key 值的變化,也就是說當(dāng)多個(gè)線程更新同一個(gè) key 值的時(shí)候,會(huì)跟原值做比較,一旦發(fā)現(xiàn)它被修改過,則拒絕執(zhí)行命令,并且會(huì)返回 nil 給客戶端。

下面還是讓我們通過一個(gè)示例來演示一下。

打開一個(gè)客戶端一,依次執(zhí)行如下命令:

flushall  //清空數(shù)據(jù)庫
watch name //監(jiān)視 name
multi     //開啟事務(wù)
set name lonely_wolf //設(shè)置 name
set age 18 // 設(shè)置 age
get name   //獲取 name
get age    //獲取 age

執(zhí)行之后得到如下效果圖:

在這里插入圖片描述

這時(shí)候再打開一個(gè)客戶端二,執(zhí)行 set name zhangsan命令:

在這里插入圖片描述

然后再回到客戶端一執(zhí)行 exec命令。這時(shí)候會(huì)發(fā)現(xiàn)直接返回了 nil,也就是事務(wù)中所有的命令都沒有被執(zhí)行(即:只要檢測到一個(gè) key 值被修改過,那么整個(gè)事務(wù)都不會(huì)被執(zhí)行):

在這里插入圖片描述

watch 原理分析

下面是一個(gè) Redis 服務(wù)的數(shù)據(jù)結(jié)構(gòu)定義:

typedef struct redisDb {
    dict *watched_keys;  //被 watch 命令監(jiān)視的 key
    int id;           //Database ID
    //...省略了其他屬性
} redisDb;

可以看到,redisDb 中的 watched_keys 存儲了一個(gè)字典,這個(gè)字典當(dāng)中的 key 存的就是被監(jiān)視的 key ,然后字典的值存的就是客戶端 id。然后每個(gè)客戶端還有一個(gè)標(biāo)記屬性 CLIENT_DIRTY_CAS,一旦我們執(zhí)行了一些如 set,sadd 等能修改 key 值對應(yīng) value 的命令,那么客戶端的 CLIENT_DIRTY_CAS 標(biāo)記屬性將會(huì)被修改,后面執(zhí)行事務(wù)提交命令 exec 時(shí)發(fā)現(xiàn)客戶端的標(biāo)記屬性被修改過(樂觀鎖的體現(xiàn)),則會(huì)拒絕執(zhí)行事務(wù)。

總結(jié)

本文主要介紹了 Redis 當(dāng)中的事務(wù)機(jī)制,在介紹事務(wù)實(shí)現(xiàn)原理的同時(shí)從傳統(tǒng)關(guān)系型數(shù)據(jù)庫的 ACID 四大特性對比分析了 Redis 當(dāng)中的事務(wù),并最終了解到了 Redis 的事務(wù)似乎并不是那么“完美”。

到此這篇關(guān)于Redis事務(wù)為什么不支持回滾 的文章就介紹到這了,更多相關(guān)Redis事務(wù)回滾 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解緩存穿透擊穿雪崩解決方案

    詳解緩存穿透擊穿雪崩解決方案

    在我們?nèi)粘5拈_發(fā)中,有時(shí)需要系統(tǒng)在極短的時(shí)間內(nèi)完成成千上萬次的讀/寫操作,這個(gè)時(shí)候不是數(shù)據(jù)庫能夠承受的,通常會(huì)引入NoSQL技術(shù)。redis技術(shù)就是NoSQL技術(shù)中的一種,但是引入redis又有可能出現(xiàn)緩存穿透,緩存擊穿,緩存雪崩等問題。本文就對這三種問題進(jìn)行較深入剖析。
    2021-05-05
  • Redis3.2.6配置文件詳細(xì)中文說明

    Redis3.2.6配置文件詳細(xì)中文說明

    本文為大家分享了Redis3.2.6配置文件詳細(xì)中文說明,非常詳細(xì)收藏起來以后工作有用
    2018-10-10
  • Redis高并發(fā)場景下秒殺超賣解決方案(秒殺場景)

    Redis高并發(fā)場景下秒殺超賣解決方案(秒殺場景)

    早起的12306購票,剛被開發(fā)出來使用的時(shí)候,12306會(huì)經(jīng)常出現(xiàn)超賣 這種現(xiàn)象,也就是說車票只剩10張了,卻被20個(gè)人買到了,這種現(xiàn)象就是超賣,今天通過本文給大家介紹Redis高并發(fā)場景下秒殺超賣解決方案,感興趣的朋友一起看看吧
    2022-04-04
  • 詳解Redis高效恢復(fù)策略內(nèi)存快照與AOF

    詳解Redis高效恢復(fù)策略內(nèi)存快照與AOF

    這篇文章主要為大家介紹了Redis高效恢復(fù)策略內(nèi)存快照與AOF及對比詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • redis并發(fā)之跳表的實(shí)現(xiàn)

    redis并發(fā)之跳表的實(shí)現(xiàn)

    跳表是一種用于實(shí)現(xiàn)有序集合的數(shù)據(jù)結(jié)構(gòu),本文主要介紹了redis并發(fā)之跳表的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • Redis常用數(shù)據(jù)類型命令實(shí)例匯總

    Redis常用數(shù)據(jù)類型命令實(shí)例匯總

    這篇文章主要介紹了Redis常用數(shù)據(jù)類型命令實(shí)例匯總,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Redis如何存儲對象與集合示例詳解

    Redis如何存儲對象與集合示例詳解

    redis是一個(gè)key-value存儲系統(tǒng)。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、 zset(sorted set --有序集合)和hash(哈希類型)本文介紹了關(guān)于Redis是如何存儲對象與集合的相關(guān)資料,需要的朋友可以參考下
    2018-05-05
  • 利用Redis實(shí)現(xiàn)SQL伸縮的方法

    利用Redis實(shí)現(xiàn)SQL伸縮的方法

    本文主要介紹了如何通過鎖和時(shí)間序列等方面來提升傳統(tǒng)數(shù)據(jù)庫的性能等方法,利用Redis實(shí)現(xiàn)SQL伸縮,供有需要的朋友們參考。
    2015-09-09
  • Redis所實(shí)現(xiàn)的Reactor模型設(shè)計(jì)方案

    Redis所實(shí)現(xiàn)的Reactor模型設(shè)計(jì)方案

    這篇文章主要介紹了Redis所實(shí)現(xiàn)的Reactor模型,本文將帶領(lǐng)讀者從源碼的角度來查看redis關(guān)于reactor模型的設(shè)計(jì),需要的朋友可以參考下
    2024-06-06
  • Redis的常用命令小結(jié)

    Redis的常用命令小結(jié)

    本文主要介紹了Redis的常用命令小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評論