真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Python:深入理解Redis事務(wù)

1. 從數(shù)據(jù)庫(kù)事務(wù)說(shuō)起

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

創(chuàng)新互聯(lián)建站服務(wù)項(xiàng)目包括樂(lè)山網(wǎng)站建設(shè)、樂(lè)山網(wǎng)站制作、樂(lè)山網(wǎng)頁(yè)制作以及樂(lè)山網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,樂(lè)山網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到樂(lè)山省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!

在數(shù)據(jù)庫(kù)相關(guān)理論中,一個(gè)邏輯工作單元想要成為事務(wù),就必須滿足 ACID,即原子性、一致性、隔離性和持久性。

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

2. redis中的事務(wù)處理

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

redis事務(wù)提供了一種“將多個(gè)命令打包, 然后一次性、按順序地執(zhí)行”的機(jī)制, 并且事務(wù)在執(zhí)行的期間不會(huì)主動(dòng)中斷 —— 服務(wù)器在執(zhí)行完事務(wù)中的所有命令之后, 才會(huì)繼續(xù)處理其他客戶(hù)端的其他命令。

Redis中的事務(wù)是可以視為一個(gè)隊(duì)列,即我們可以通過(guò)MULTI開(kāi)始一個(gè)事務(wù),這相當(dāng)于我們聲明了一個(gè)命令隊(duì)列。接下來(lái),我們向Redis中提交的每條命令,都會(huì)被排入這個(gè)命令隊(duì)列。當(dāng)我們輸入EXEC命令時(shí),將觸發(fā)當(dāng)前事務(wù),這相當(dāng)于我們從命令隊(duì)列中取出命令并執(zhí)行,所以Redis中一個(gè)事務(wù)從開(kāi)始到執(zhí)行會(huì)經(jīng)歷  開(kāi)始事務(wù) 、  命令入隊(duì) 和  執(zhí)行事務(wù) 三個(gè)階段。下面是一個(gè)在Redis中使用事務(wù)的簡(jiǎn)單示例:

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中的事務(wù)和通常意義上的事務(wù)基本上是一致的,即

  • 事務(wù)是由一系列操作組成的單個(gè)邏輯工作執(zhí)行單元。特別地,因?yàn)樵赗edis中命令是存儲(chǔ)在一個(gè)隊(duì)列中,所以,事務(wù)中的所有命令都會(huì)按順序執(zhí)行,并且在執(zhí)行事務(wù)的過(guò)程中不會(huì)被客戶(hù)端發(fā)送的其它命令中斷。
  • 事務(wù)是一個(gè)原子操作,事物中的命令只有兩種執(zhí)行結(jié)果,即全部執(zhí)行或者全部不執(zhí)行。如果客戶(hù)端在使用MULTI命令開(kāi)啟事務(wù)后因?yàn)橐馔舛鴽](méi)有執(zhí)行EXEC命令,則事務(wù)中的所有命令都不會(huì)執(zhí)行。同理,如果客戶(hù)端在使用MULTI命令開(kāi)啟事務(wù)后執(zhí)行EXEC命令,則事務(wù)中的所有命令都會(huì)執(zhí)行。
  • Redis中的事務(wù)可以使用DISCARD命令來(lái)清空一個(gè)命令隊(duì)列,并放棄對(duì)事務(wù)的執(zhí)行。如果命令在入隊(duì)時(shí)發(fā)生錯(cuò)誤,Redis將在客戶(hù)端調(diào)用EXEC命令時(shí)拒絕執(zhí)行并取消事務(wù),但是在EXEC命令執(zhí)行后發(fā)生的錯(cuò)誤,Redis將選擇自動(dòng)忽略。

3.redis事務(wù)執(zhí)行過(guò)程

一個(gè)事務(wù)從開(kāi)始到執(zhí)行會(huì)經(jīng)歷以下三個(gè)階段:

  • 1)開(kāi)始事務(wù)。
  • 2)命令入隊(duì)。
  • 3)執(zhí)行事務(wù)。

下面將分別介紹事務(wù)的這三個(gè)階段。

1)開(kāi)始事務(wù)

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


redis>
 MULTI
OK

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

Python:深入理解Redis事務(wù)

圖1 客戶(hù)端狀態(tài)轉(zhuǎn)換

2)命令入隊(duì)

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


redis>
 SET msg 
"hello moto"
OK

redis> GET msg
"hello moto"

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


redis>
 MULTI
OK

redis> SET msg "hello moto"
QUEUED

redis> GET msg
QUEUED

其原理如圖2所示

Python:深入理解Redis事務(wù)

圖2. 命令入隊(duì)

3)執(zhí)行事務(wù)

前面說(shuō)到, 當(dāng)客戶(hù)端進(jìn)入事務(wù)狀態(tài)之后, 客戶(hù)端發(fā)送的命令就會(huì)被放進(jìn)事務(wù)隊(duì)列里。

但其實(shí)并不是所有的命令都會(huì)被放進(jìn)事務(wù)隊(duì)列, 其中的例外就是 EXEC 、 DISCARD 、 MULTI 和 WATCH 這四個(gè)命令 —— 當(dāng)這四個(gè)命令從客戶(hù)端發(fā)送到服務(wù)器時(shí), 它們會(huì)像客戶(hù)端處于非事務(wù)狀態(tài)一樣, 直接被服務(wù)器執(zhí)行:

Python:深入理解Redis事務(wù)

圖3 執(zhí)行事務(wù)

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

執(zhí)行事務(wù)中的命令所得的結(jié)果會(huì)以 FIFO 的順序保存到一個(gè)回復(fù)隊(duì)列中。

當(dāng)事務(wù)隊(duì)列里的所有命令被執(zhí)行完之后,EXEC命令會(huì)將回復(fù)隊(duì)列作為自己的執(zhí)行結(jié)果返回給客戶(hù)端, 客戶(hù)端從事務(wù)狀態(tài)返回到非事務(wù)狀態(tài), 至此, 事務(wù)執(zhí)行完畢。

4.redis事務(wù)命令

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

Python:深入理解Redis事務(wù)

圖4 事務(wù)命令

使用案例:

  • 正常執(zhí)行
Python:深入理解Redis事務(wù)

圖5. 正常執(zhí)行

  • 放棄事務(wù)
Python:深入理解Redis事務(wù)

圖6 放棄事務(wù)

  • 若在事務(wù)隊(duì)列中存在命令性錯(cuò)誤,則執(zhí)行EXEC命令時(shí),所有命令都不會(huì)執(zhí)行
Python:深入理解Redis事務(wù)

圖7 命令錯(cuò)誤

  • 若在事務(wù)隊(duì)列中存在語(yǔ)法性錯(cuò)誤,則執(zhí)行EXEC命令時(shí),其他正確命令會(huì)被執(zhí)行,錯(cuò)誤命令拋出異常。
Python:深入理解Redis事務(wù)

圖8 語(yǔ)法錯(cuò)誤

  • 使用watch

使用watch檢測(cè)balance,事務(wù)期間balance數(shù)據(jù)未變動(dòng),事務(wù)執(zhí)行成功

Python:深入理解Redis事務(wù)

圖9 watch用法1

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

Python:深入理解Redis事務(wù)

圖10 watch用法2

Python:深入理解Redis事務(wù)

圖11 修改balance

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

在每個(gè)代表數(shù)據(jù)庫(kù)的 redis.h/redisDb 結(jié)構(gòu)類(lèi)型中, 都保存了一個(gè) watched_keys 字典, 字典的鍵是這個(gè)數(shù)據(jù)庫(kù)被監(jiān)視的鍵, 而字典的值則是一個(gè)鏈表, 鏈表中保存了所有監(jiān)視這個(gè)鍵的客戶(hù)端。

比如說(shuō),以下字典就展示了一個(gè) watched_keys 字典的例子:

Python:深入理解Redis事務(wù)

圖11 watch實(shí)現(xiàn)的原理

其中, 鍵 key1 正在被 client2 、 client5 和 client1 三個(gè)客戶(hù)端監(jiān)視, 其他一些鍵也分別被其他別的客戶(hù)端監(jiān)視著。

WATCH 命令的作用, 就是將當(dāng)前客戶(hù)端和要監(jiān)視的鍵在 watched_keys 中進(jìn)行關(guān)聯(lián)。

舉個(gè)例子, 如果當(dāng)前客戶(hù)端為 client10086 , 那么當(dāng)客戶(hù)端執(zhí)行 WATCH key1 key2 時(shí), 前面展示的 watched_keys 將被修改成這個(gè)樣子:

Python:深入理解Redis事務(wù)

圖12 watch實(shí)現(xiàn)原理2

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

  • watch的觸發(fā)
    在任何對(duì)數(shù)據(jù)庫(kù)鍵空間(key space)進(jìn)行修改的命令成功執(zhí)行之后 (比如FLUSHDB、SET、DEL、LPUSH、SADD、ZREM,諸如此類(lèi)),multi.c/touchWatchedKey函數(shù)都會(huì)被調(diào)用 —— 它檢查數(shù)據(jù)庫(kù)的watched_keys字典, 看是否有客戶(hù)端在監(jiān)視已經(jīng)被命令修改的鍵, 如果有的話, 程序?qū)⑺斜O(jiān)視這個(gè)/這些被修改鍵的客戶(hù)端的REDIS_DIRTY_CAS選項(xiàng)打開(kāi):
Python:深入理解Redis事務(wù)

圖13 watch的觸發(fā)

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

  • 如果客戶(hù)端的 REDIS_DIRTY_CAS 選項(xiàng)已經(jīng)被打開(kāi),那么說(shuō)明被客戶(hù)端監(jiān)視的鍵至少有一個(gè)已經(jīng)被修改了,事務(wù)的安全性已經(jīng)被破壞。服務(wù)器會(huì)放棄執(zhí)行這個(gè)事務(wù),直接向客戶(hù)端返回空回復(fù),表示事務(wù)執(zhí)行失敗。
  • 如果 REDIS_DIRTY_CAS 選項(xiàng)沒(méi)有被打開(kāi),那么說(shuō)明所有監(jiān)視鍵都安全,服務(wù)器正式執(zhí)行事務(wù)。

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

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

  • 原子性

事務(wù)具有原子性指的是, 數(shù)據(jù)庫(kù)將事務(wù)中的多個(gè)操作當(dāng)作一個(gè)整體來(lái)執(zhí)行,服務(wù)器要么就執(zhí)行事務(wù)中的所有操作, 要么就一個(gè)操作也不執(zhí)行。對(duì)于Redis的事務(wù)功能來(lái)說(shuō),事務(wù)隊(duì)列中的命令要么就全部都執(zhí)行,要么就一個(gè)都不執(zhí)行,因此, Redis的事務(wù)是具有原子性的。

Redis的事務(wù)和傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)事務(wù)的最大區(qū)別在于, Redis不支持事務(wù)回滾機(jī)制(rollback), 即使事務(wù)隊(duì)列中的某個(gè)命令在執(zhí)行期間出現(xiàn)了錯(cuò)誤,整個(gè)事務(wù)也會(huì)繼續(xù)執(zhí)行下去,直到將事務(wù)隊(duì)列中的所有命令都執(zhí)行完畢為止。 下面展示了即使RPUSH命令在執(zhí)行期間出現(xiàn)了錯(cuò)誤,事務(wù)的后續(xù)命令也會(huì)繼續(xù)執(zhí)行下去, 并且之前執(zhí)行的命令也不會(huì)有任何影響:

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

不支持事務(wù)回滾是因?yàn)檫@種復(fù)雜的功能和Redis追求簡(jiǎn)單高效的設(shè)計(jì)主旨不相符,并且Redis事務(wù)的執(zhí)行時(shí)錯(cuò)誤通常都是編程錯(cuò)誤產(chǎn)生的, 這種錯(cuò)誤通常只會(huì)出現(xiàn)在開(kāi)發(fā)環(huán)境中, 而很少會(huì)在實(shí)際的生產(chǎn)環(huán)境中出現(xiàn)。

  • 一致性

事務(wù)的一致性是指,如果數(shù)據(jù)庫(kù)執(zhí)行前是一致的,那么在事務(wù)執(zhí)行后,無(wú)論事務(wù)是否執(zhí)行成功,數(shù)據(jù)庫(kù)也應(yīng)該是一致的。

  • 隔離性
    事務(wù)的隔離性指的是,即使數(shù)據(jù)庫(kù)中有多個(gè)事務(wù)并發(fā)地執(zhí)行,各個(gè)事務(wù)之間也不會(huì)互相 影響,并且在并發(fā)狀態(tài)下執(zhí)行的事務(wù)和串行執(zhí)行的事務(wù)產(chǎn)生的結(jié)果完全相同。
    因?yàn)镽edis使用 單線程的方式來(lái)執(zhí)行事務(wù)(以及事務(wù)隊(duì)列中的命令),并且服務(wù)器保證, 在執(zhí)行事務(wù)期間不會(huì)對(duì)事務(wù)進(jìn)行中斷,因此, Redis的事務(wù)總是以串行的方式運(yùn)行的,并且  事務(wù) 也總是具有隔離性的。
  • 持久性

事務(wù)的耐久性指的是,當(dāng)一個(gè)事務(wù)執(zhí)行完畢時(shí),執(zhí)行這個(gè)事務(wù)所得的結(jié)果巳經(jīng)被保存到 永久性存儲(chǔ)介質(zhì)(比如硬盤(pán))里面了, 即使服務(wù)器在事務(wù)執(zhí)行完畢 之后停機(jī), 執(zhí)行事務(wù)所得的結(jié)果也不會(huì)丟失。Redis事務(wù)的耐久性由服務(wù)器所使用持久化模式?jīng)Q定的:(1) 當(dāng)服務(wù)器在無(wú)持久化的內(nèi)存模式下運(yùn)作時(shí),事務(wù)不具有耐久性。因?yàn)橐坏┓?wù)器停機(jī),服務(wù)器所有的數(shù)據(jù)都將丟失。(2) 當(dāng)服務(wù)器在ROB持久化模式下運(yùn)作時(shí),事務(wù)同樣不具有耐久性。因?yàn)榉?wù)器只會(huì)在特定的保存條件下才會(huì)執(zhí)行BGSAVE命令,并且異步執(zhí)行的BGSAVE命令不能保證事務(wù)的數(shù)據(jù)第一時(shí)間被保存到硬盤(pán)上。(3) 當(dāng)服務(wù)器運(yùn)行在AOF持久化模式下,并且appendfsync選項(xiàng)的值為always時(shí),程序總會(huì)在執(zhí)行命令之后調(diào)用同步(sync)函數(shù),將命令數(shù)據(jù)真正地保存到硬盤(pán)里。


當(dāng)前名稱(chēng):Python:深入理解Redis事務(wù)
本文URL:http://weahome.cn/article/ggjpee.html

其他資訊

在線咨詢(xún)

微信咨詢(xún)

電話咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部