最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解MySQL中事務(wù)的持久性實(shí)現(xiàn)原理

 更新時(shí)間:2021年01月28日 15:19:01   作者:X先生  
這篇文章主要介紹了詳解MySQL中事務(wù)的持久性實(shí)現(xiàn)原理,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下

前言

說到數(shù)據(jù)庫(kù)事務(wù),大家腦子里一定很容易蹦出一堆事務(wù)的相關(guān)知識(shí),如事務(wù)的ACID特性,隔離級(jí)別,解決的問題(臟讀,不可重復(fù)讀,幻讀)等等,但是可能很少有人真正的清楚事務(wù)的這些特性又是怎么實(shí)現(xiàn)的,為什么要有四個(gè)隔離級(jí)別。

在之前的文章我們已經(jīng)了解了MySQL中事務(wù)的隔離性的實(shí)現(xiàn)原理,今天就繼續(xù)來聊一聊MySQL持久性的實(shí)現(xiàn)原理。

當(dāng)然MySQL博大精深,文章疏漏之處在所難免,歡迎批評(píng)指正。

說明

MySQL的事務(wù)實(shí)現(xiàn)邏輯是位于引擎層的,并且不是所有的引擎都支持事務(wù)的,下面的說明都是以InnoDB引擎為基準(zhǔn)。

InnoDB讀寫數(shù)據(jù)原理

在往下學(xué)習(xí)之前,我們需要先來了解下InnoDB是怎么來讀寫數(shù)據(jù)的。我們知道數(shù)據(jù)庫(kù)的數(shù)據(jù)都是存放在磁盤中的,然后我們也知道磁盤I/O的成本是很大的,如果每次讀寫數(shù)據(jù)都要訪問磁盤,數(shù)據(jù)庫(kù)的效率就會(huì)非常低。為了解決這個(gè)問題,InnoDB提供了 Buffer Pool 作為訪問數(shù)據(jù)庫(kù)數(shù)據(jù)的緩沖。

Buffer Pool 是位于內(nèi)存的,包含了磁盤中部分?jǐn)?shù)據(jù)頁(yè)的映射。當(dāng)需要讀取數(shù)據(jù)時(shí),InnoDB會(huì)首先嘗試從Buffer Pool中讀取,讀取不到的話就會(huì)從磁盤讀取后放入Buffer Pool;當(dāng)寫入數(shù)據(jù)時(shí),會(huì)先寫入Buffer Pool的頁(yè)面,并把這樣的頁(yè)面標(biāo)記為dirty,并放到專門的flush list上,這些修改的數(shù)據(jù)頁(yè)會(huì)在后續(xù)某個(gè)時(shí)刻被刷新到磁盤中(這一過程稱為刷臟,由其他后臺(tái)線程負(fù)責(zé)) 。如下圖所示:

這樣設(shè)計(jì)的好處是可以把大量的磁盤I/O轉(zhuǎn)成內(nèi)存讀寫,并且把對(duì)一個(gè)頁(yè)面的多次修改merge成一次I/O操作(刷臟一次刷入整個(gè)頁(yè)面),避免每次讀寫操作都訪問磁盤,從而大大提升了數(shù)據(jù)庫(kù)的性能。

持久性定義

持久性是指事務(wù)一旦提交,它對(duì)數(shù)據(jù)庫(kù)的改變就應(yīng)該是永久性的,接下來的其他操作或故障不應(yīng)該對(duì)本次事務(wù)的修改有任何影響。

通過前面的介紹,我們知道InnoDB使用 Buffer Pool  來提高讀寫的性能。但是 Buffer Pool 是在內(nèi)存的,是易失性的,如果一個(gè)事務(wù)提交了事務(wù)后,MySQL突然宕機(jī),且此時(shí)Buffer Pool中修改的數(shù)據(jù)還沒有刷新到磁盤中的話,就會(huì)導(dǎo)致數(shù)據(jù)的丟失,事務(wù)的持久性就無法保證。

為了解決這個(gè)問題,InnoDB引入了 redo log來實(shí)現(xiàn)數(shù)據(jù)修改的持久化。當(dāng)數(shù)據(jù)修改時(shí),InnoDB除了修改Buffer Pool中的數(shù)據(jù),還會(huì)在redo log 記錄這次操作,并保證redo log早于對(duì)應(yīng)的頁(yè)面落盤(一般在事務(wù)提交的時(shí)候),也就是常說的WAL。若MySQL突然宕機(jī)了且還沒有把數(shù)據(jù)刷回磁盤,重啟后,MySQL會(huì)通過已經(jīng)寫入磁盤的redo log來恢復(fù)沒有被刷新到磁盤的數(shù)據(jù)頁(yè)。

實(shí)現(xiàn)原理:redo log

為了提高性能,和數(shù)據(jù)頁(yè)類似,redo log 也包括兩部分:一是內(nèi)存中的日志緩沖(redo log buffer),該部分日志是易失性的;二是磁盤上的重做日志文件(redo log file),該部分日志是持久的。redo log是物理日志,記錄的是數(shù)據(jù)庫(kù)中物理頁(yè)的情況 。

當(dāng)數(shù)據(jù)發(fā)生修改時(shí),InnoDB不僅會(huì)修改Buffer Pool中的數(shù)據(jù),也會(huì)在redo log buffer記錄這次操作;當(dāng)事務(wù)提交時(shí),會(huì)對(duì)redo log buffer進(jìn)行刷盤,記錄到redo log file中。如果MySQL宕機(jī),重啟時(shí)可以讀取redo log file中的數(shù)據(jù),對(duì)數(shù)據(jù)庫(kù)進(jìn)行恢復(fù)。這樣就不需要每次提交事務(wù)都實(shí)時(shí)進(jìn)行刷臟了。

寫入過程

注意點(diǎn):

  • 先修改Buffer Pool,后寫 redo log buffer。
  • redo日志比數(shù)據(jù)頁(yè)先寫回磁盤:事務(wù)提交的時(shí)候,會(huì)把redo log buffer寫入redo log file,寫入成功才算提交成功(也有其他場(chǎng)景觸發(fā)寫入,這里就不展開了),而Buffer Pool的數(shù)據(jù)由后臺(tái)線程在后續(xù)某個(gè)時(shí)刻寫入磁盤。
  • 刷臟的時(shí)候一定會(huì)保證對(duì)應(yīng)的redo log已經(jīng)落盤了,也即是所謂的WAL(預(yù)寫式日志),否則會(huì)有數(shù)據(jù)丟失的可能性。

好處

事務(wù)提交的時(shí)候,寫入redo log 相比于直接刷臟的好處主要有三點(diǎn):

刷臟是隨機(jī)I/O,但寫redo log 是順序I/O,順序I/O可比隨機(jī)I/O快多了,不需要。
刷臟是以數(shù)據(jù)頁(yè)(Page)為單位的,即使一個(gè)Page只有一點(diǎn)點(diǎn)修改也要整頁(yè)寫入;而redo log中只包含真正被修改的部分,數(shù)據(jù)量非常小,無效IO大大減少。
刷臟的時(shí)候可能要刷很多頁(yè)的數(shù)據(jù),無法保證原子性(例如只寫了一部分?jǐn)?shù)據(jù)就失敗了),而redo log buffer 向 redo log file 寫log block,是按512個(gè)字節(jié),也就是一個(gè)扇區(qū)的大小進(jìn)行寫入,扇區(qū)是寫入的最小單位,因此可以保證寫入是必定成功的。

先寫redo log還是先修改數(shù)據(jù)

一次DML可能涉及到數(shù)據(jù)的修改和redo log的記錄,那它們的執(zhí)行順序是怎么樣的呢?網(wǎng)上的文章有的說先修改數(shù)據(jù),后記錄redo log,有的說先記錄redo log,后改數(shù)據(jù),那真實(shí)的情況是如何呢?

首先通過上面的說明我們知道,redo log buffer在事務(wù)提交的時(shí)候就會(huì)寫入redo log file的,而刷臟則是在后續(xù)的某個(gè)時(shí)刻,所以可以確定的是先記錄redo log,后修改data page(WAL當(dāng)然是日志先寫啦)。

那接下來的問題就是先寫redo log buffer還是先修改Buffer Pool了。要了解這個(gè)問題,我們先要了解InnoDB中,一次DML的執(zhí)行過程是怎么樣的。一次DML的執(zhí)行過程涉及了數(shù)據(jù)的修改,加鎖,解鎖,redo log的記錄和undo log的記錄等,也是需要保證原子性的,而InnoDB通過MTR(Mini-transactions)來保證一次DML操作的原子性。

首先來看MTR的定義:

 An internal phase of InnoDB processing, when making changes at the physical level to internal data structures during DML operations. A Mini-transactions (mtr) has no notion of rollback; multiple Mini-transactionss can occur within a single transaction. Mini-transactionss write information to the redo log that is used during crash recovery. A Mini-transactions can also happen outside the context of a regular transaction, for example during purge processing by background threads. 見 https://dev.mysql.com/doc/refman/8.0/en/glossary.html

MTR 是一個(gè)短原子操作,不能回滾,因?yàn)樗旧砭褪窃拥?。?shù)據(jù)頁(yè)的變更必須通過MTR,MTR 會(huì)把DML操作對(duì)數(shù)據(jù)頁(yè)的修改記錄到 redo log里。

下面來簡(jiǎn)單看下MTR的過程:

  • MTR初始化的時(shí)候會(huì)初始化一份 mtr_buf
  • 當(dāng)修改數(shù)據(jù)時(shí),在對(duì)內(nèi)存Buffer Pool中的頁(yè)面進(jìn)行修改的同時(shí),還會(huì)生成redo log record,保存在mtr_buf中。
  • 在執(zhí)行mtr_commit函數(shù)提交本MTR的時(shí)候,會(huì)將mtr_buf中的redo log record更新到redo log buffer中,同時(shí)將臟頁(yè)添加到flush list,供后續(xù)刷臟使用。在log buffer中,每接收到496字節(jié)的log record,就將這組log record包裝一個(gè)12字節(jié)的block header和一個(gè)4字節(jié)的block tailer,成為一個(gè)512字節(jié)的log block,方便刷盤的時(shí)候?qū)R512字節(jié)刷盤。

由此可見,InnoDB是先修改Buffer Pool,后寫redo log buffer的。

恢復(fù)數(shù)據(jù)的過程

在任何情況下,InnoDB啟動(dòng)時(shí)都會(huì)嘗試執(zhí)行recovery操作。在恢復(fù)過程中,需要redo log參與,而如果還開啟了binlog,那就還需要binlog、undo log的參與。因?yàn)橛锌赡軘?shù)據(jù)已經(jīng)寫入binlog了,但是redo log還沒有刷盤的時(shí)候數(shù)據(jù)庫(kù)就奔潰了(事務(wù)是InnoDB引擎的特性,修改了數(shù)據(jù)不一定提交了,而binlog是MySQL服務(wù)層的特性,修改數(shù)據(jù)就會(huì)記錄了),這時(shí)候就需要redo log,binlog和undo log三者的參與來判斷是否有還沒提交的事務(wù),未提交的事務(wù)進(jìn)行回滾或者提交操作。

下面來簡(jiǎn)單說下僅利用redo log恢復(fù)數(shù)據(jù)的過程:

  • 啟動(dòng)InnoDB時(shí),找到最近一次Checkpoint的位置,利用Checkpoint LSN去找大于該LSN的redo log進(jìn)行日志恢復(fù)。
  • 如果中間恢復(fù)失敗了也沒影響,再次恢復(fù)的時(shí)候還是從上次保存成功的Checkpoint的位置繼續(xù)恢復(fù)。

Recover過程:故障恢復(fù)包含三個(gè)階段:Analysis,Redo和Undo。Analysis階段的任務(wù)主要是利用Checkpoint及Log中的信息確認(rèn)后續(xù)Redo和Undo階段的操作范圍,通過Log修正Checkpoint中記錄的Dirty Page集合信息,并用其中涉及最小的LSN位置作為下一步Redo的開始位置RedoLSN。同時(shí)修正Checkpoint中記錄的活躍事務(wù)集合(未提交事務(wù)),作為Undo過程的回滾對(duì)象;Redo階段從Analysis獲得的RedoLSN出發(fā),重放所有的Log中的Redo內(nèi)容,注意這里也包含了未Commit事務(wù);最后Undo階段對(duì)所有未提交事務(wù)利用Undo信息進(jìn)行回滾,通過Log的PrevLSN可以順序找到事務(wù)所有需要回滾的修改。具體見 http://catkang.github.io/2019/01/16/crash-recovery.html

什么是LSN?

LSN也就是log sequence number,也日志的序列號(hào),是一個(gè)單調(diào)遞增的64位無符號(hào)整數(shù)。redo log和數(shù)據(jù)頁(yè)都保存著LSN,可以用作數(shù)據(jù)恢復(fù)的依據(jù)。LSN更大的表示所引用的日志記錄所描述的變化發(fā)生在更后面。

什么是Checkpoint?

Checkpoint表示一個(gè)保存點(diǎn),在這個(gè)點(diǎn)之前的數(shù)據(jù)頁(yè)的修改(log LSN<Checkpoint LSN)都已經(jīng)寫入磁盤文件了。InnoDB每次刷盤之后都會(huì)記錄Checkpoint,把最新的redo log LSN 記錄到Checkpoint LSN 里,方便恢復(fù)數(shù)據(jù)的時(shí)候作為起始點(diǎn)的判斷。

以上就是詳解MySQL中事務(wù)的持久性實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于MySQL 事務(wù)的持久性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 通過實(shí)例解析MySql CURRENT_TIMESTAMP函數(shù)

    通過實(shí)例解析MySql CURRENT_TIMESTAMP函數(shù)

    這篇文章主要介紹了通過實(shí)例解析MySql CURRENT_TIMESTAMP函數(shù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • MySQL數(shù)據(jù)庫(kù)實(shí)現(xiàn)高可用架構(gòu)之MHA的實(shí)戰(zhàn)

    MySQL數(shù)據(jù)庫(kù)實(shí)現(xiàn)高可用架構(gòu)之MHA的實(shí)戰(zhàn)

    本文主要介紹了MySQL數(shù)據(jù)庫(kù)實(shí)現(xiàn)高可用架構(gòu)之MHA的實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • MySQL5.7限制general_log日志大小的實(shí)現(xiàn)

    MySQL5.7限制general_log日志大小的實(shí)現(xiàn)

    MySQL5.7.41中為避免通用查詢?nèi)罩緂eneral_log快速增長(zhǎng)占用硬盤空間,可以通過定時(shí)任務(wù)執(zhí)行腳本進(jìn)行每日備份或清理,從而限制其大小,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • MySQL8.0如何配置Path環(huán)境變量

    MySQL8.0如何配置Path環(huán)境變量

    將MySQL的bin目錄添加到系統(tǒng)的環(huán)境變量中,可以避免每次登錄MySQL時(shí)都需要輸入cd命令,具體步驟如下:首先,右鍵桌面上的“此電腦”選擇“屬性”,點(diǎn)擊左側(cè)的“高級(jí)系統(tǒng)設(shè)置”,在“系統(tǒng)屬性”對(duì)話框中選擇“高級(jí)”選項(xiàng)卡,點(diǎn)擊“環(huán)境變量”
    2024-11-11
  • MySQL存儲(chǔ)引擎中的MyISAM和InnoDB區(qū)別詳解

    MySQL存儲(chǔ)引擎中的MyISAM和InnoDB區(qū)別詳解

    這篇文章主要介紹了MySQL存儲(chǔ)引擎中的MyISAM和InnoDB區(qū)別詳解,本文總結(jié)了MyISAM與InnoDB的11點(diǎn)區(qū)別,需要的朋友可以參考下
    2015-03-03
  • 詳解MySQL數(shù)據(jù)庫(kù)設(shè)置主從同步的方法

    詳解MySQL數(shù)據(jù)庫(kù)設(shè)置主從同步的方法

    最近一直在研究mysql的主從同步問題,現(xiàn)在網(wǎng)上也有很多資料,現(xiàn)在感覺寫的都很好(當(dāng)初感覺寫的很差,是因?yàn)樽约旱念I(lǐng)悟較差),于是想跟大家分享一下自己配置的整個(gè)過程和經(jīng)驗(yàn)。有需要的朋友歐美可以參考借鑒,感興趣的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2016-11-11
  • MySQL數(shù)據(jù)同步到Doris的四種方式

    MySQL數(shù)據(jù)同步到Doris的四種方式

    這篇文章給大家介紹了MySQL數(shù)據(jù)同步到Doris的四種方式,CSV文件方式,JDBC 編碼方式,JDBC Catalog 方式和Binlog Load 方式,并通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • MySQL實(shí)例crash的案例詳細(xì)分析

    MySQL實(shí)例crash的案例詳細(xì)分析

    這篇文章主要給大家介紹了關(guān)于MySQL實(shí)例crash的相關(guān)資料,文中通過示例代碼的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mysql具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • 庫(kù)名表名大小寫問題與sqlserver兼容的啟動(dòng)配置方法

    庫(kù)名表名大小寫問題與sqlserver兼容的啟動(dòng)配置方法

    庫(kù)名表名大小寫問題與sqlserver兼容的啟動(dòng)配置方法,需要的朋友可以參考下。
    2010-12-12
  • Mysql如何按照范圍區(qū)間創(chuàng)建分區(qū)表

    Mysql如何按照范圍區(qū)間創(chuàng)建分區(qū)表

    在Mysql的范圍分區(qū)表定義中,分區(qū)范圍需要連續(xù)并且不會(huì)有覆蓋,定義范圍分區(qū)表時(shí),使用VALUES LESS THAN操作符,這篇文章主要介紹了Mysql如何按照范圍區(qū)間創(chuàng)建分區(qū)表,需要的朋友可以參考下
    2024-08-08

最新評(píng)論

宣汉县| 大关县| 溧水县| 城口县| 报价| 安新县| 泾川县| 封丘县| 武川县| 泗水县| 高州市| 河北区| 水富县| 张北县| 白城市| 新丰县| 吉林省| 朝阳县| 鸡东县| 高淳县| 临城县| 新干县| 丰城市| 辉南县| 哈巴河县| 巴里| 嫩江县| 深圳市| 长丰县| 无锡市| 简阳市| 南安市| 余江县| 安康市| 兰溪市| 泸西县| 乌什县| 阳城县| 长葛市| 萨迦县| 怀安县|