日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 一致性读_mysql/mariadb知识点总结(27):一致性读,快照读

發布時間:2024/9/3 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 一致性读_mysql/mariadb知识点总结(27):一致性读,快照读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在本博客中,”mysql”是一個系列文章,這些文章主要對mysql/mariadb的常用知識點進行了總結,每一篇博客總結的知識點有所不同,具體內容可參考mysql文章列表。

mysql文章列表直達鏈接:mysql知識點總結

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

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

數據的一致性:通常指關聯數據之間的邏輯關系是否正確和完整。

數據庫的一致性:是指數據庫從一個一致性狀態變到另一個一致性狀態。

好吧,專業的術語說的很模糊,我們來通俗的、不嚴謹的舉個例子,可能有不當之處,但是方便理解。

數據的一致性

先說說什么是數據的一致性,舉例如下。

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

這時,我們再來回顧一下數據的一致性的概念:

數據的一致性通常指關聯數據之間的邏輯關系是否正確和完整。

現在,你明白上述”專業術語”的意思了嗎?

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

數據庫的一致性

你在網上搜索”什么是數據庫的一致性”,往往會看到如下通俗的舉例。

銀行的數據庫中有2個用戶,A用戶和B用戶,上午10點時,A用戶的賬戶中有5萬元,B用戶的賬戶中有10萬元,目前,數據是處在一個一致狀態的,因為,A用戶發現自己的錢沒少沒多,B用戶發現自己的錢沒少沒多,一切都很正常,上午11點時,B用戶要向A用戶轉賬,B用戶要向A用戶轉賬2萬元,那么,轉賬完成后,B用戶的賬戶中有8萬元,A用戶的賬戶中有7萬元,此刻,又處于一個一致狀態,雖然B賬戶的錢少了2萬,A賬戶多了2萬,但是這是轉賬后的結果,從邏輯上講,也是對的,上午12點,A用戶準備退出此銀行,想把錢轉向其他銀行,于是,A用戶把自己賬戶中的7萬元取走了,此時,銀行只剩下了以個B用戶,所有錢都是B用戶的錢,一共8萬,此時,銀行的數據庫又處于一個一致性狀態。這就是數據庫的一致性。

這時,我們再來回顧一下數據庫的一致性的概念:

數據庫的一致性:是指數據庫從一個一致性狀態變到另一個一致性狀態。

其實我感覺,數據庫的一致性想要表達的意思就是,數據庫中的數據保持在一致狀態,雖然數據有可能會變化,但是狀態一直是一致的。

怎樣保持數據一致性

還是以備份時的場景為例,如果我們3點開始備份,則必須保證備份中的所有數據都是3點那一刻的樣子,即使備份需要持續一段時間,我們仍然要確保備份完成后,數據就是3點那一刻的樣子,即保證備份對于備份開始那一刻來說,數據是一致的,那么我們怎么做到呢?

一般我們有兩種做法

第一種方法:備份開始時對所有表加鎖,備份結束之前不能修改數據庫,這樣,不管備份持續多長時間,都能保證對于備份開始那一刻來說,數據庫中的數據是一致的,因為數據壓根沒變,它一直處于同一個一致狀態中。但是這樣做的缺點就是,一旦數據庫開始備份,則無法對數據庫進行寫操作,最多只能進行讀操作。

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

可重讀隔離級別下的一致性讀

君子動口不動手,該出手時就出手。

我們一起來動手實踐一下,即可更加明白,怎樣通過”可重讀”隔離級別保證完成一致性讀。

首先,先來回顧一下”可重讀”隔離級別下的”幻讀”,我們將兩個數據庫會話中的事務隔離級別都設置成可重讀,然后在兩個會話中同時開啟兩個事務,如下圖所示,紅線以下的操作請嚴格按照序號的順序進行操作。

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

注意:上例中第7步執行的update語句并沒有指定任何條件,相當于更新表中的所有行的對應字段,如果你指定了條件,并且沒有更新到”隱藏”的行,那么可能無法看到幻讀現象

但是,在備份數據時,所有備份操作都是”讀操作”,并不包含更新操作,所以,如果我們把所有備份操作都放在一個單獨的”事務”中,并且這個事務的隔離級別為”可重讀”時,是不會出現”幻讀”的問題的,就實現了針對某一時間點內所有數據的一致性讀,保證了讀取數據時,數據的一致性。

但是,真的如我們想象的這樣簡單嗎?我們來繼續做實驗。

假設,我們使用下圖中會話A中的事務進行數據備份,會話A中首先要開啟一個事務A,而且這個事務的隔離級別為”可重讀”,我們假設此事務中的所有讀操作都是數據備份的操作,如下圖所示

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

下圖中的會話A中的事務仍然表示我們用來備份的”事務”,這是一個獨立的、隔離級別為”可重讀”的事務,假設,我們下午3點開始備份,我們啟動了一個”可重讀”的獨立事務,下午3點時,t1表中只有兩條數據,雖然3點時,我們開啟了事務,但是,此刻我們并沒有開始備份操作(讀操作),我們想要先準備一些數據以后,再開始實際的備份工作??墒?#xff0c;就在這個時間段內,有人對t1表進行了寫操作,在這之后,我們開始進行備份操作,結果發現,備份出的數據并不是下午3點時的兩條數據,而是3條數據,如下圖所示。

怎么會這樣???????????

我一直認為,如果一個事務處在”可重讀”級別下,只要事務開始,就代表當前事務對數據進行了”快照”,看來我錯了。

換句話說就是,我一直以為,當事務處于”可重讀”隔離級別時,只要start transaction這個語句一開始,就代表當前事務對這一刻的數據進行了快照,我一直都理解錯了,看來,我不應該以start transaction語句開始的時間點作為”快照”建立的時間點。那么,我應該以哪個時間點作為”快照”建立的時間點呢?官方的解釋如下。

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.

也就是說,當事務處于”可重讀”隔離級別時,并不是事務開始時就代表快照建立,而是事務中的第一個查詢語句執行時,快照點才會被建立。

這也解釋了為什么上述兩例中,兩個事務的隔離級別都為可重讀,但是第一個示例在事務開始后就實現了”一致性讀”,而第二個示例在事務開始的時間點,沒有實現”一致性讀”的原因,因為,第一個示例中,事務開始以后,立馬執行了一個select語句,而第二個示例中,事務開始以后,并沒有馬上執行select語句,在這段時間里,數據已經發生了改變,等到執行select語句時,快照才會建立,所以,對于執行select語句時的時間點,數據是一致的,但是對于事務開始的時間點來說,數據是不一致的。

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

START TRANSACTION WITH consistent snapshot

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

那么我們來實驗一下,看看到底行不行,仍然使用事務A模擬備份的事務,事務A的隔離級別是”可重讀”,示例如下

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

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

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

總結

以上是生活随笔為你收集整理的mysql 一致性读_mysql/mariadb知识点总结(27):一致性读,快照读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。