亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python:深入理解Redis事務

發布時間:2020-08-12 23:02:47 來源:ITPUB博客 閱讀:171 作者:千鋒Python唐小強 欄目:編程語言

1. 從數據庫事務說起

通常我們提及數據庫都不可避免的要提到事務,那么什么是事務呢?事務是指作為單個邏輯工作單元執行的一系列操作。所以,首先事務是一系列操作,這一系列操作具有二態性,即完全地執行或者完全地不執行。因此事務處理可以確保除非事務單元內的所有操作的成功完成,否則不會想數據庫更新面向數據的資源。我們這里舉一個例子,數據庫中除查詢操作以外,插入(Insert)、刪除(Delete)和更新(Update)這三種操作都會對數據造成影響,因為事務處理能夠保證一系列操作可以完全地執行或者完全不執行,因此在一個事務被提交以后,該事務中的任何一條SQL語句在被執行的時候,都會生成一條撤銷日志(Undo Log),而撤銷日志中記錄的是和當前擦作完全相反的操作,比如刪除的相反操作是插入,插入的相反操作是刪除等。我們通常所說的事務回滾其實就是去執行這些插銷日志里的相反操作,這同樣告訴我們一個道理,只有事務中的一系列操作完全執行的情況下可以回滾,如果是在意外情況下導致事務中的一系列操作沒有完全執行,這個時候我們是不能保證數據一定可以回滾的。

在數據庫相關理論中,一個邏輯工作單元想要成為事務,就必須滿足 ACID,即原子性、一致性、隔離性和持久性。

  • (1)原子性:原子性這個概念其實就是指,一個事務內的所有SQL操作都是一個整體,因此只有所有的SQL操作都完全執行成功,該事務方可以認為提交成功。如果在提交事務過程中某一條SQL語句執行失敗,則整個事務必須回滾到事務提交前的狀態。
  • (2)一致性:而一致性這個概念則是指,事務在完成的時候,必須要保證所有的數據都保持一致的狀態,而落實到數據庫的各個組成部分上,則要求開發人員能夠保證數據、索引、約束、日志等在事務前后具備一致性。
  • (3)隔離性:隔離性這個概念主要針對并發,其核心思想就是不同的并發事務對數據產生的修改必須是相互隔離的,假設有兩個不同的事務A和B并發執行,那么對A來講,它在執行前的狀態只有兩種,即B執行前和B執行后。同理,對B來講同樣是如此,這樣的特性我們就稱為隔離性。
  • (4)持久性:持久性相對簡單,是指事務完成以后它對數據的影響是永久性的。

2. Redis中的事務處理

我們對數據庫中事務處理的相關理論有了一個基本的認識,或許這個世界上的數據庫系統千差萬別,但我相信在事務處理這個問題上它們最終會殊途同歸,就像我們解決并發過程中的沖突問題,常規的做法依然是加鎖一樣,這是我之所以要花費精力去理解和解釋這些理論知識的原因,技術可謂是日新月異,如果我們總是一味地為新技術而疲于奔命,那么或許我們會漸漸地失去對這個行業的熱愛,我相信原理永遠比框架更為重要。

redis事務提供了一種“將多個命令打包, 然后一次性、按順序地執行”的機制, 并且事務在執行的期間不會主動中斷 —— 服務器在執行完事務中的所有命令之后, 才會繼續處理其他客戶端的其他命令。

Redis中的事務是可以視為一個隊列,即我們可以通過MULTI開始一個事務,這相當于我們聲明了一個命令隊列。接下來,我們向Redis中提交的每條命令,都會被排入這個命令隊列。當我們輸入EXEC命令時,將觸發當前事務,這相當于我們從命令隊列中取出命令并執行,所以Redis中一個事務從開始到執行會經歷  開始事務 、  命令入隊 和  執行事務 三個階段。下面是一個在Redis中使用事務的簡單示例:

127
.0
.0
.1
:6379> 
MULTI 

OK
127 .0 .0 .1 :6379> SET Book_Name " GIt Pro"
QUEUED
127 .0 .0 .1 :6379> SADD Program_Language " C++" " C#" " Jave" " Python"  
QUEUED
127 .0 .0 .1 :6379> GET Book_Name
QUEUED
127 .0 .0 .1 :6379> EXEC
1) OK
2) ( integer) 4
3) " GIt Pro"

我們可以注意到Redis中的事務和通常意義上的事務基本上是一致的,即

  • 事務是由一系列操作組成的單個邏輯工作執行單元。特別地,因為在Redis中命令是存儲在一個隊列中,所以,事務中的所有命令都會按順序執行,并且在執行事務的過程中不會被客戶端發送的其它命令中斷。
  • 事務是一個原子操作,事物中的命令只有兩種執行結果,即全部執行或者全部不執行。如果客戶端在使用MULTI命令開啟事務后因為意外而沒有執行EXEC命令,則事務中的所有命令都不會執行。同理,如果客戶端在使用MULTI命令開啟事務后執行EXEC命令,則事務中的所有命令都會執行。
  • Redis中的事務可以使用DISCARD命令來清空一個命令隊列,并放棄對事務的執行。如果命令在入隊時發生錯誤,Redis將在客戶端調用EXEC命令時拒絕執行并取消事務,但是在EXEC命令執行后發生的錯誤,Redis將選擇自動忽略。

3.redis事務執行過程

一個事務從開始到執行會經歷以下三個階段:

  • 1)開始事務。
  • 2)命令入隊。
  • 3)執行事務。

下面將分別介紹事務的這三個階段。

1)開始事務

MULTI命令的執行標記著事務的開始:


redis>
 MULTI

OK

這個命令唯一做的就是, 將客戶端的 REDIS_MULTI 選項打開, 讓客戶端從非事務狀態切換到事務狀態。

Python:深入理解Redis事務

圖1 客戶端狀態轉換

2)命令入隊

當客戶端處于非事務狀態下時, 所有發送給服務器端的命令都會立即被服務器執行:


redis>
 SET msg 
"hello moto"

OK

redis> GET msg
"hello moto"

但是, 當客戶端進入事務狀態之后, 服務器在收到來自客戶端的命令時, 不會立即執行命令, 而是將這些命令全部放進一個事務隊列里, 然后返回QUEUED, 表示命令已入隊:


redis>
 MULTI

OK

redis> SET msg "hello moto"
QUEUED

redis> GET msg
QUEUED

其原理如圖2所示

Python:深入理解Redis事務

圖2. 命令入隊

3)執行事務

前面說到, 當客戶端進入事務狀態之后, 客戶端發送的命令就會被放進事務隊列里。

但其實并不是所有的命令都會被放進事務隊列, 其中的例外就是 EXEC 、 DISCARD 、 MULTI 和 WATCH 這四個命令 —— 當這四個命令從客戶端發送到服務器時, 它們會像客戶端處于非事務狀態一樣, 直接被服務器執行:

Python:深入理解Redis事務

圖3 執行事務

如果客戶端正處于事務狀態, 那么當EXEC命令執行時, 服務器根據客戶端所保存的事務隊列, 以先進先出(FIFO)的方式執行事務隊列中的命令: 最先入隊的命令最先執行, 而最后入隊的命令最后執行。

執行事務中的命令所得的結果會以 FIFO 的順序保存到一個回復隊列中。

當事務隊列里的所有命令被執行完之后,EXEC命令會將回復隊列作為自己的執行結果返回給客戶端, 客戶端從事務狀態返回到非事務狀態, 至此, 事務執行完畢。

4.redis事務命令

redis事務使用了multi、exec、discard、watch、unwatch命令,命令的作用如圖4所示:

Python:深入理解Redis事務

圖4 事務命令

使用案例:

  • 正常執行
Python:深入理解Redis事務

圖5. 正常執行

  • 放棄事務
Python:深入理解Redis事務

圖6 放棄事務

  • 若在事務隊列中存在命令性錯誤,則執行EXEC命令時,所有命令都不會執行
Python:深入理解Redis事務

圖7 命令錯誤

  • 若在事務隊列中存在語法性錯誤,則執行EXEC命令時,其他正確命令會被執行,錯誤命令拋出異常。
Python:深入理解Redis事務

圖8 語法錯誤

  • 使用watch

使用watch檢測balance,事務期間balance數據未變動,事務執行成功

Python:深入理解Redis事務

圖9 watch用法1

WATCH命令用于在事務開始之前監視任意數量的鍵: 當調用EXEC命令執行事務時, 如果任意一個被監視的鍵已經被其他客戶端修改了, 那么整個事務不再執行, 直接返回失敗。

Python:深入理解Redis事務

圖10 watch用法2

Python:深入理解Redis事務

圖11 修改balance

  • WATCH 命令的實現

在每個代表數據庫的 redis.h/redisDb 結構類型中, 都保存了一個 watched_keys 字典, 字典的鍵是這個數據庫被監視的鍵, 而字典的值則是一個鏈表, 鏈表中保存了所有監視這個鍵的客戶端。

比如說,以下字典就展示了一個 watched_keys 字典的例子:

Python:深入理解Redis事務

圖11 watch實現的原理

其中, 鍵 key1 正在被 client2 、 client5 和 client1 三個客戶端監視, 其他一些鍵也分別被其他別的客戶端監視著。

WATCH 命令的作用, 就是將當前客戶端和要監視的鍵在 watched_keys 中進行關聯。

舉個例子, 如果當前客戶端為 client10086 , 那么當客戶端執行 WATCH key1 key2 時, 前面展示的 watched_keys 將被修改成這個樣子:

Python:深入理解Redis事務

圖12 watch實現原理2

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

  • watch的觸發
    在任何對數據庫鍵空間(key space)進行修改的命令成功執行之后 (比如FLUSHDB、SET、DEL、LPUSH、SADD、ZREM,諸如此類),multi.c/touchWatchedKey函數都會被調用 —— 它檢查數據庫的watched_keys字典, 看是否有客戶端在監視已經被命令修改的鍵, 如果有的話, 程序將所有監視這個/這些被修改鍵的客戶端的REDIS_DIRTY_CAS選項打開:
Python:深入理解Redis事務

圖13 watch的觸發

當客戶端發送 EXEC 命令、觸發事務執行時, 服務器會對客戶端的狀態進行檢查:

  • 如果客戶端的 REDIS_DIRTY_CAS 選項已經被打開,那么說明被客戶端監視的鍵至少有一個已經被修改了,事務的安全性已經被破壞。服務器會放棄執行這個事務,直接向客戶端返回空回復,表示事務執行失敗。
  • 如果 REDIS_DIRTY_CAS 選項沒有被打開,那么說明所有監視鍵都安全,服務器正式執行事務。

5.  事務的 ACID 性質

在Redis中,事務總是具有原子性(Atomicity)、一致性(Consistency)和隔離性(Isolation),并且當Redis運行在某種特定的持久化模式下,事務也具有持久性性(Durability)。

  • 原子性

事務具有原子性指的是, 數據庫將事務中的多個操作當作一個整體來執行,服務器要么就執行事務中的所有操作, 要么就一個操作也不執行。對于Redis的事務功能來說,事務隊列中的命令要么就全部都執行,要么就一個都不執行,因此, Redis的事務是具有原子性的。

Redis的事務和傳統的關系型數據庫事務的最大區別在于, Redis不支持事務回滾機制(rollback), 即使事務隊列中的某個命令在執行期間出現了錯誤,整個事務也會繼續執行下去,直到將事務隊列中的所有命令都執行完畢為止。 下面展示了即使RPUSH命令在執行期間出現了錯誤,事務的后續命令也會繼續執行下去, 并且之前執行的命令也不會有任何影響:

127
.0
.0
.1
:6379> 
set 
msg 
hello

OK

127 .0 .0 .1 :6379> multi
OK

127 .0 .0 .1 :6379> sadd fruit apple banana cherry
QUEUED

127 .0 .0 .1 :6379> rpush msg bye redis
QUEUED

127 .0 .0 .1 :6379> sadd alphabet a b c
QUEUED

127 .0 .0 .1 :6379> exec
1) ( integer) 3
2) ( error) WRONGTYPE Operation against a key holding the wrong kind of value
3) ( integer) 3

不支持事務回滾是因為這種復雜的功能和Redis追求簡單高效的設計主旨不相符,并且Redis事務的執行時錯誤通常都是編程錯誤產生的, 這種錯誤通常只會出現在開發環境中, 而很少會在實際的生產環境中出現。

  • 一致性

事務的一致性是指,如果數據庫執行前是一致的,那么在事務執行后,無論事務是否執行成功,數據庫也應該是一致的。

  • 隔離性
    事務的隔離性指的是,即使數據庫中有多個事務并發地執行,各個事務之間也不會互相 影響,并且在并發狀態下執行的事務和串行執行的事務產生的結果完全相同。
    因為Redis使用 單線程的方式來執行事務(以及事務隊列中的命令),并且服務器保證, 在執行事務期間不會對事務進行中斷,因此, Redis的事務總是以串行的方式運行的,并且  事務 也總是具有隔離性的。
  • 持久性

事務的耐久性指的是,當一個事務執行完畢時,執行這個事務所得的結果巳經被保存到 永久性存儲介質(比如硬盤)里面了, 即使服務器在事務執行完畢 之后停機, 執行事務所得的結果也不會丟失。Redis事務的耐久性由服務器所使用持久化模式決定的:(1) 當服務器在無持久化的內存模式下運作時,事務不具有耐久性。因為一旦服務器停機,服務器所有的數據都將丟失。(2) 當服務器在ROB持久化模式下運作時,事務同樣不具有耐久性。因為服務器只會在特定的保存條件下才會執行BGSAVE命令,并且異步執行的BGSAVE命令不能保證事務的數據第一時間被保存到硬盤上。(3) 當服務器運行在AOF持久化模式下,并且appendfsync選項的值為always時,程序總會在執行命令之后調用同步(sync)函數,將命令數據真正地保存到硬盤里。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永胜县| 开鲁县| 哈尔滨市| 永年县| 华蓥市| 石屏县| 固始县| 建德市| 乌兰浩特市| 塘沽区| 两当县| 将乐县| 玛沁县| 高唐县| 紫金县| 武邑县| 石楼县| 西安市| 永宁县| 巫山县| 阿勒泰市| 当涂县| 获嘉县| 兴义市| 和平区| 湛江市| 尚义县| 敖汉旗| 多伦县| 朝阳区| 皋兰县| 娄烦县| 太和县| 余江县| 怀仁县| 宝鸡市| 桦南县| 于田县| 呼和浩特市| 河北省| 江口县|