日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

mysql中的數(shù)據(jù)一致性、一致性讀、快照讀詳解

 jxl0716 2019-07-09

在本博客中,'mysql'是一個(gè)系列文章,這些文章主要對(duì)mysql/mariadb的常用知識(shí)點(diǎn)進(jìn)行了總結(jié),每一篇博客總結(jié)的知識(shí)點(diǎn)有所不同,具體內(nèi)容可參考mysql文章列表。

mysql文章列表直達(dá)鏈接:mysql知識(shí)點(diǎn)總結(jié)

 mysql/mariadb知識(shí)點(diǎn)總結(jié)(27):一致性讀,快照讀

我們來考慮一個(gè)問題,如果我們要備份數(shù)據(jù),我們一定要保證備份出的數(shù)據(jù)的可用性,如果備份后的數(shù)據(jù)在恢復(fù)以后,無法正常使用,那么備份出的數(shù)據(jù)也就失去了備份的意義,數(shù)據(jù)可用的前提就是數(shù)據(jù)的正確性、完整性、一致性。正確性和完整性比較容易理解,一致性只通過字面理解不太容易,我們來舉個(gè)小例子理解一下。

不過在舉例之前,我們還是先來看一下'一致性'的一些專業(yè)解釋,雖然這些專業(yè)解釋不容易理解,但是沒有關(guān)系,我們先大概了解一下,在看完后面通俗的示例后你自然會(huì)理解。

數(shù)據(jù)的一致性:通常指關(guān)聯(lián)數(shù)據(jù)之間的邏輯關(guān)系是否正確和完整。

數(shù)據(jù)庫的一致性:是指數(shù)據(jù)庫從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài)。

好吧,專業(yè)的術(shù)語說的很模糊,我們來通俗的、不嚴(yán)謹(jǐn)?shù)呐e個(gè)例子,可能有不當(dāng)之處,但是方便理解。

數(shù)據(jù)的一致性

先說說什么是數(shù)據(jù)的一致性,舉例如下。

假設(shè),今天下午3點(diǎn)的時(shí)候,小朱的'某寶'賬戶中有200元錢,小朱想要在網(wǎng)上買一輛自行車,這輛自行車售價(jià)198,然后小朱把這輛自行車加入到了購物車中,但是并沒有付款,那么某寶認(rèn)為,小朱在3點(diǎn)的時(shí)候,是有能力購買這輛自行車的,于是,某寶就記錄了一下,小朱在3點(diǎn)的時(shí)候有能力購買這輛自行車(這里只是假設(shè)),假設(shè)某寶3點(diǎn)開始備份數(shù)據(jù)庫,那么,理論上來說,某寶備份出的數(shù)據(jù)應(yīng)該是3點(diǎn)那一刻所有數(shù)據(jù)的狀態(tài),某寶把這次備份命名為'某寶在3點(diǎn)時(shí)的數(shù)據(jù)備份',但是某寶的用戶辣么多,數(shù)據(jù)量辣么大,備份總是需要時(shí)間的,假設(shè)小朱是某寶的第88888888888個(gè)用戶,從某寶備份數(shù)據(jù)開始,到備份結(jié)束,需要2個(gè)小時(shí),而備份到小朱的賬戶信息時(shí)需要一個(gè)半小時(shí),換句話說,某寶從3點(diǎn)開始備份,備份完成,需要到5點(diǎn),可能會(huì)在4點(diǎn)半備份到小朱的數(shù)據(jù),那么如果,在3點(diǎn)之后到4點(diǎn)半之前這段時(shí)間內(nèi),小朱從'某寶'賬戶中轉(zhuǎn)出了100元,還在賬戶中剩余了100元,那么,在4點(diǎn)半的時(shí)候,某寶備份到的小朱的賬戶數(shù)據(jù)將是'小朱的賬戶中有100元',可是我們不要忘了,某寶是從3點(diǎn)開始備份的,某寶會(huì)認(rèn)為這次備份中的數(shù)據(jù)都是3點(diǎn)時(shí)的數(shù)據(jù),那么,如果出現(xiàn)上述的情況,這次備份的數(shù)據(jù)就變成了'3點(diǎn)時(shí),小朱的賬戶中有100元',這與實(shí)際情況不符 啊,這與實(shí)際情況'不一致'啊,3點(diǎn)那一刻,小朱的賬戶中明明有'200'元,可是備份中卻顯示'3點(diǎn)那一刻,小朱的賬戶中有100元',如果在3點(diǎn)時(shí),小朱的賬戶只有100元,是沒有能力購買那輛價(jià)值198元的自行車的,也就是說,在3點(diǎn)那一刻,所有的'交易'邏輯都不成立了,這就是數(shù)據(jù)的不一致,在某一時(shí)間點(diǎn),關(guān)聯(lián)數(shù)據(jù)之間的邏輯關(guān)系不正確,或者不完整,這就是數(shù)據(jù)不一致,那么我們遇到過這種情況嗎?貌似沒有,某寶很可靠,某寶中的數(shù)據(jù)都是一致的,即使在3點(diǎn)開始備份,備份需要兩個(gè)小時(shí),備份期間即使各個(gè)用戶的賬戶信息發(fā)生變化,某寶還是能夠記錄下備份開始時(shí)那一刻時(shí),所有信息的樣子,而且關(guān)聯(lián)數(shù)據(jù)之間的邏輯關(guān)系都是正常的。這就是所謂的'數(shù)據(jù)的一致性'。那么,怎么樣才能讓數(shù)據(jù)'一致'呢?我們一會(huì)兒再聊。

這時(shí),我們?cè)賮砘仡櫼幌聰?shù)據(jù)的一致性的概念:

數(shù)據(jù)的一致性通常指關(guān)聯(lián)數(shù)據(jù)之間的邏輯關(guān)系是否正確和完整。

現(xiàn)在,你明白上述'專業(yè)術(shù)語'的意思了嗎?

可能還是不理解,但是起碼比剛才好多了吧。

數(shù)據(jù)庫的一致性

你在網(wǎng)上搜索'什么是數(shù)據(jù)庫的一致性',往往會(huì)看到如下通俗的舉例。

銀行的數(shù)據(jù)庫中有2個(gè)用戶,A用戶和B用戶,上午10點(diǎn)時(shí),A用戶的賬戶中有5萬元,B用戶的賬戶中有10萬元,目前,數(shù)據(jù)是處在一個(gè)一致狀態(tài)的,因?yàn)?,A用戶發(fā)現(xiàn)自己的錢沒少?zèng)]多,B用戶發(fā)現(xiàn)自己的錢沒少?zèng)]多,一切都很正常,上午11點(diǎn)時(shí),B用戶要向A用戶轉(zhuǎn)賬,B用戶要向A用戶轉(zhuǎn)賬2萬元,那么,轉(zhuǎn)賬完成后,B用戶的賬戶中有8萬元,A用戶的賬戶中有7萬元,此刻,又處于一個(gè)一致狀態(tài),雖然B賬戶的錢少了2萬,A賬戶多了2萬,但是這是轉(zhuǎn)賬后的結(jié)果,從邏輯上講,也是對(duì)的,上午12點(diǎn),A用戶準(zhǔn)備退出此銀行,想把錢轉(zhuǎn)向其他銀行,于是,A用戶把自己賬戶中的7萬元取走了,此時(shí),銀行只剩下了以個(gè)B用戶,所有錢都是B用戶的錢,一共8萬,此時(shí),銀行的數(shù)據(jù)庫又處于一個(gè)一致性狀態(tài)。這就是數(shù)據(jù)庫的一致性。

這時(shí),我們?cè)賮砘仡櫼幌聰?shù)據(jù)庫的一致性的概念:

數(shù)據(jù)庫的一致性:是指數(shù)據(jù)庫從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài)。

其實(shí)我感覺,數(shù)據(jù)庫的一致性想要表達(dá)的意思就是,數(shù)據(jù)庫中的數(shù)據(jù)保持在一致狀態(tài),雖然數(shù)據(jù)有可能會(huì)變化,但是狀態(tài)一直是一致的。

怎樣保持?jǐn)?shù)據(jù)一致性

還是以備份時(shí)的場景為例,如果我們3點(diǎn)開始備份,則必須保證備份中的所有數(shù)據(jù)都是3點(diǎn)那一刻的樣子,即使備份需要持續(xù)一段時(shí)間,我們?nèi)匀灰_保備份完成后,數(shù)據(jù)就是3點(diǎn)那一刻的樣子,即保證備份對(duì)于備份開始那一刻來說,數(shù)據(jù)是一致的,那么我們?cè)趺醋龅侥兀?/p>

一般我們有兩種做法

第一種方法:備份開始時(shí)對(duì)所有表加鎖,備份結(jié)束之前不能修改數(shù)據(jù)庫,這樣,不管備份持續(xù)多長時(shí)間,都能保證對(duì)于備份開始那一刻來說,數(shù)據(jù)庫中的數(shù)據(jù)是一致的,因?yàn)閿?shù)據(jù)壓根沒變,它一直處于同一個(gè)一致狀態(tài)中。但是這樣做的缺點(diǎn)就是,一旦數(shù)據(jù)庫開始備份,則無法對(duì)數(shù)據(jù)庫進(jìn)行寫操作,最多只能進(jìn)行讀操作。

第二種方法:在備份開始時(shí)對(duì)所有數(shù)據(jù)進(jìn)行一個(gè)'快照',由于'快照'記錄了開始備份時(shí)那一刻所有數(shù)據(jù)的樣子,所以,在這個(gè)'快照'范圍內(nèi)讀取出的所有數(shù)據(jù),也具有一致性,在mysql中,我們可以利用事務(wù)實(shí)現(xiàn)類似'快照'的功能,如果表使用的存儲(chǔ)引擎為innodb,那么我們則可以利用事務(wù)的'隔離性',保證數(shù)據(jù)的'一致性',之前的文章已經(jīng)總結(jié)了innodb的事務(wù)的'隔離級(jí)別'(如果你不知道我在說什么,請(qǐng)參考之前對(duì)事務(wù)的總結(jié)),不同的隔離級(jí)別下,事務(wù)之間擁有不同的隔離性,所以,并不是所有的隔離級(jí)別都能在備份的場景中保證數(shù)據(jù)的一致性。如果你讀過之前的文章,那你一定想到了,通過'可重讀'隔離級(jí)別,即可在備份的場景中,保證數(shù)據(jù)的一致性,這時(shí)候,有的人會(huì)說,事務(wù)在'可重讀'的隔離界別下,不是會(huì)出現(xiàn)'幻讀'的情況嗎?如果我們?cè)趥浞輹r(shí),出現(xiàn)幻讀,不就會(huì)備份出不一致的數(shù)據(jù)嗎?但是,回顧之前的總結(jié),我們可以發(fā)現(xiàn),如果當(dāng)前事務(wù)處于'可重讀'隔離級(jí)別下,如果在當(dāng)前事務(wù)中不進(jìn)行更新操作,是不會(huì)出現(xiàn)幻讀的情況的,而恰巧,在備份時(shí),相當(dāng)于對(duì)數(shù)據(jù)進(jìn)行讀操作,我們只要能夠保證,將所有備份操作放在一個(gè)單獨(dú)的事務(wù)中,并且將這個(gè)事務(wù)的隔離級(jí)別設(shè)置為'可重讀'即可,因?yàn)檫@個(gè)事務(wù)中只進(jìn)行備份操作,并不進(jìn)行其他操作,所以,并不會(huì)出現(xiàn)'幻讀'的情況,從而就保證了整個(gè)備份過程中,所有數(shù)據(jù)對(duì)于某個(gè)時(shí)間點(diǎn)來說,是一致的,從而保證了數(shù)據(jù)的'一致性讀','一致性讀'也被稱為'快照讀'。

可重讀隔離級(jí)別下的一致性讀

君子動(dòng)口不動(dòng)手,該出手時(shí)就出手。

我們一起來動(dòng)手實(shí)踐一下,即可更加明白,怎樣通過'可重讀'隔離級(jí)別保證完成一致性讀。

首先,先來回顧一下'可重讀'隔離級(jí)別下的'幻讀',我們將兩個(gè)數(shù)據(jù)庫會(huì)話中的事務(wù)隔離級(jí)別都設(shè)置成可重讀,然后在兩個(gè)會(huì)話中同時(shí)開啟兩個(gè)事務(wù),如下圖所示,紅線以下的操作請(qǐng)嚴(yán)格按照序號(hào)的順序進(jìn)行操作。

mysql/mariadb知識(shí)點(diǎn)總結(jié)(27):一致性讀,快照讀

如上圖所示,剛開始時(shí),事務(wù)A和事務(wù)B中查詢出的數(shù)據(jù)均為2條數(shù)據(jù),即使事務(wù)B中插入了新數(shù)據(jù),并且提交了事務(wù)B,然后在事務(wù)A中查詢時(shí),仍然只能查詢出兩條數(shù)據(jù),只有在事務(wù)A中更新執(zhí)行了更新操作以后,才能夠在事務(wù)A中看到事務(wù)B中新增的數(shù)據(jù),這就是'可重讀'級(jí)別下的'幻讀'。

注意:上例中第8步執(zhí)行的update語句并沒有指定任何條件,相當(dāng)于更新表中的所有行的對(duì)應(yīng)字段,如果你指定了條件,并且沒有更新到'隱藏'的行,那么可能無法看到幻讀現(xiàn)象

但是,在備份數(shù)據(jù)時(shí),所有備份操作都是'讀操作',并不包含更新操作,所以,如果我們把所有備份操作都放在一個(gè)單獨(dú)的'事務(wù)'中,并且這個(gè)事務(wù)的隔離級(jí)別為'可重讀'時(shí),是不會(huì)出現(xiàn)'幻讀'的問題的,就實(shí)現(xiàn)了針對(duì)某一時(shí)間點(diǎn)內(nèi)所有數(shù)據(jù)的一致性讀,保證了讀取數(shù)據(jù)時(shí),數(shù)據(jù)的一致性。

但是,真的如我們想象的這樣簡單嗎?我們來繼續(xù)做實(shí)驗(yàn)。

假設(shè),我們使用下圖中會(huì)話A中的事務(wù)進(jìn)行數(shù)據(jù)備份,會(huì)話A中首先要開啟一個(gè)事務(wù)A,而且這個(gè)事務(wù)的隔離級(jí)別為'可重讀',我們假設(shè)此事務(wù)中的所有讀操作都是數(shù)據(jù)備份的操作,如下圖所示

mysql/mariadb知識(shí)點(diǎn)總結(jié)(27):一致性讀,快照讀

如果說,上圖中的第1步操作表示備份開始,備份的時(shí)間為下午3點(diǎn),備份完成需要兩個(gè)小時(shí),那么,我們必須保證,只要這個(gè)事務(wù)一開始,在這個(gè)事務(wù)中讀到的所有數(shù)據(jù),都是下午3點(diǎn)時(shí)的樣子(就好像事務(wù)開始時(shí)的那一刻的所有數(shù)據(jù)做了'快照'一樣),那么按照上圖所示,似乎與我們想象的一樣,因?yàn)榧词乖趥浞萜陂g,對(duì)數(shù)據(jù)庫進(jìn)行寫操作(操作3與操作4),似乎也沒有影響到數(shù)據(jù)的一致性,在事務(wù)A中無論何時(shí)讀到的數(shù)據(jù)都是事務(wù)開始時(shí)的樣子(下午3點(diǎn)時(shí)的樣子),事務(wù)A之外的操作并不能影響到事務(wù)A的讀取。這樣真的萬無一失嗎?我們來看下面的例子。

下圖中的會(huì)話A中的事務(wù)仍然表示我們用來備份的'事務(wù)',這是一個(gè)獨(dú)立的、隔離級(jí)別為'可重讀'的事務(wù),假設(shè),我們下午3點(diǎn)開始備份,我們啟動(dòng)了一個(gè)'可重讀'的獨(dú)立事務(wù),下午3點(diǎn)時(shí),t1表中只有兩條數(shù)據(jù),雖然3點(diǎn)時(shí),我們開啟了事務(wù),但是,此刻我們并沒有開始備份操作(讀操作),我們想要先準(zhǔn)備一些數(shù)據(jù)以后,再開始實(shí)際的備份工作??墒牵驮谶@個(gè)時(shí)間段內(nèi),有人對(duì)t1表進(jìn)行了寫操作,在這之后,我們開始進(jìn)行備份操作,結(jié)果發(fā)現(xiàn),備份出的數(shù)據(jù)并不是下午3點(diǎn)時(shí)的兩條數(shù)據(jù),而是3條數(shù)據(jù),如下圖所示。

mysql/mariadb知識(shí)點(diǎn)總結(jié)(27):一致性讀,快照讀

怎么會(huì)這樣???????????

我一直認(rèn)為,如果一個(gè)事務(wù)處在'可重讀'級(jí)別下,只要事務(wù)開始,就代表當(dāng)前事務(wù)對(duì)數(shù)據(jù)進(jìn)行了'快照',看來我錯(cuò)了。

換句話說就是,我一直以為,當(dāng)事務(wù)處于'可重讀'隔離級(jí)別時(shí),只要start transaction這個(gè)語句一開始,就代表當(dāng)前事務(wù)對(duì)這一刻的數(shù)據(jù)進(jìn)行了快照,我一直都理解錯(cuò)了,看來,我不應(yīng)該以start transaction語句開始的時(shí)間點(diǎn)作為'快照'建立的時(shí)間點(diǎn)。那么,我應(yīng)該以哪個(gè)時(shí)間點(diǎn)作為'快照'建立的時(shí)間點(diǎn)呢?官方的解釋如下。

https://dev./doc/refman/5.5/en/innodb-consistent-read.html

If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction. You can get a fresher snapshot for your queries by committing the current transaction and after that issuing new queries.

也就是說,當(dāng)事務(wù)處于'可重讀'隔離級(jí)別時(shí),并不是事務(wù)開始時(shí)就代表快照建立,而是事務(wù)中的第一個(gè)查詢語句執(zhí)行時(shí),快照點(diǎn)才會(huì)被建立。

這也解釋了為什么上述兩例中,兩個(gè)事務(wù)的隔離級(jí)別都為可重讀,但是第一個(gè)示例在事務(wù)開始后就實(shí)現(xiàn)了'一致性讀',而第二個(gè)示例在事務(wù)開始的時(shí)間點(diǎn),沒有實(shí)現(xiàn)'一致性讀'的原因,因?yàn)椋谝粋€(gè)示例中,事務(wù)開始以后,立馬執(zhí)行了一個(gè)select語句,而第二個(gè)示例中,事務(wù)開始以后,并沒有馬上執(zhí)行select語句,在這段時(shí)間里,數(shù)據(jù)已經(jīng)發(fā)生了改變,等到執(zhí)行select語句時(shí),快照才會(huì)建立,所以,對(duì)于執(zhí)行select語句時(shí)的時(shí)間點(diǎn),數(shù)據(jù)是一致的,但是對(duì)于事務(wù)開始的時(shí)間點(diǎn)來說,數(shù)據(jù)是不一致的。

難道,如果我們想要在事務(wù)開始時(shí)就建立快照,就必須在事務(wù)開始后立馬手動(dòng)執(zhí)行一條select語句嗎?不是的,mysql為我們提供了另一種選擇,就是使用如下語句啟動(dòng)一個(gè)'可重讀'的事務(wù)。

START TRANSACTION WITH consistent snapshot

執(zhí)行上述語句等效于執(zhí)行start transaction 之后,馬上執(zhí)行一條 select 語句(即 start transaction 語句執(zhí)行的同時(shí)建立'快照')

那么我們來實(shí)驗(yàn)一下,看看到底行不行,仍然使用事務(wù)A模擬備份的事務(wù),事務(wù)A的隔離級(jí)別是'可重讀',示例如下

mysql/mariadb知識(shí)點(diǎn)總結(jié)(27):一致性讀,快照讀

從上圖可以看出,使用start transaction with consistent snapshot;命令啟動(dòng)事務(wù),就表示啟動(dòng)事務(wù)的同時(shí)就建立快照,也就是說,只要事務(wù)開始,就能保證'一致性讀'。

好了,mysql中的一致性讀(快照讀)就總結(jié)到這里吧。

你可能會(huì)覺得我特別啰嗦,但是對(duì)于某些朋友來說,他們就是需要有人啰嗦一點(diǎn),才能更容易的理解這些知識(shí)點(diǎn)吧,希望我的啰嗦可以幫到你,你肯定猜到我要說什么了,沒錯(cuò),求推薦,求收藏,求評(píng)論,求點(diǎn)贊~~~~~~

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多