跟面試官侃半小時MySQL事務,說完原子性、一致性、持久性的實現

提到MySQL的事務,我相信對MySQL有了解的同窗都能聊上幾句,不管是面試求職,仍是平常開發,MySQL的事務都跟咱們息息相關。html

而事務的ACID(即原子性Atomicity、一致性Consistency、隔離性Isolation、持久性Durability)能夠說涵蓋了事務的所有知識點,因此,咱們不只要知道ACID是什麼,還要了解ACID背後的實現,只有這樣,不管在平常開發仍是面試求職,都能無往而不利。git

上一篇 跟面試官侃半小時MySQL事務隔離性,從基本概念深刻到實現 主要圍繞「隔離性」展開,從基本概念,到隔離性的實現,最後以一個實戰案例進行融會貫通。本篇內容將介紹原子性、一致性、持久性相關實現,因爲這部份內容可能不少人會相對陌生,由於平常業務開發可能不太會去接觸和深究,可是瞭解完後,你對MySQL會有更深入的認識。github

1.基本概念

  • 原子性。

整個事務是不可分割的最小單位,事務中任何一個語句執行失敗,全部已經執行成功的語句也要回滾,整個數據庫狀態要恢復到執行事務前到狀態。面試

  • 一致性。

事務將數據庫從一種狀態轉變爲下一種一致的狀態。在事務的先後,數據庫的完整性約束沒有被破壞。(事務的acid不是徹底正交的,尤爲是一致性,可能跟原子性、隔離性都有必定關係,後面會看到)數據庫

  • 持久性。

事務一旦提交,那麼就是永久性的,不會由於宕機等故障致使數據丟失(外力影響不保證,好比磁盤損害)。持久性是保證了數據庫的高可靠性(High Reliability),而不是高可用性(Hign Availability)。高可用性並不能經過事務來保證。緩存

2.持久性的實現

MySQL的innoDB存儲引擎,使用Redo log保證了事務的持久性。併發

當事務提交時,必須先將事務的全部日誌寫入日誌文件進行持久化,就是咱們常說的WAL(write ahead log)機制(這個技術是保障持久性的關鍵技術,在HBase中也扮演重要角色,有興趣的同窗能夠參考我以前關於HBase的文章)。這樣才能保證斷電或宕機等狀況發生後,已提交的事務不會丟失,這個能力稱爲 crash-safe。mvc

下面深刻聊一聊redo log的機制,給你們更深入的理解。分佈式

Redo log包括兩部分,重作日誌緩衝(redo log buffer)和重作日誌文件(redo log file),前者是易失的緩存,後者是持久化的文件。3d

舉一個事務的例子:

  • 步驟1:begin;
  • 步驟2:insert into t1 …r
  • 步驟3:insert into t2 …
  • 步驟4:commit;

這個事務的寫入過程實際拆解以下:

跟面試官侃半小時MySQL事務,說完原子性、一致性、持久性的實現

 

innodb緩衝池的概念本文就不展開說明了,之後有機會能夠展開說一下。

重點關注在這個事務提交前,將 redo log 的寫入拆成了兩個步驟,prepare 和 commit,這就是"兩階段提交」。

爲何要採用兩階段提交呢?

實際上,兩階段提交是分佈式系統經常使用的機制。MySQL使用了兩階段提交後,也是爲了保證事務的持久性。Redo log 和bingo 有一個共同的數據字段,叫 XID,崩潰恢復的時候,會按順序掃描 redo log。

  • 假設在寫入binlog前系統崩潰,那麼數據庫恢復後順序掃描 redo log,碰到只有 parepare、而沒有 commit 的 redo log,就拿着 XID 去 binlog 找對應的事務,並且binlog也沒寫入,因此事務就直接回滾了。
  • 假設在寫入binlog以後,事務提交前數據庫崩潰,那麼數據庫恢復後順序掃描 redo log,碰到既有 prepare、又有 commit 的 redo log,就直接提交,保證數據不丟失。

這個事務要往兩個表中插入記錄,插入數據的過程當中,生成的日誌都得先寫入redo log buffer ,等到commit的時候,才真正把日誌寫到 redo log 文件。(固然,這裏不絕對,由於redo log buffer可能由於其餘緣由被迫刷新到redo log)。

而爲了確保每第二天志都能寫入日誌文件,在每次將重作日誌緩衝 寫入 重作日誌文件 後,InnoDB存儲引擎都須要調用一次fsync操做,確保寫入了磁盤。

對於redo log的持久化,能夠以下圖所示。

跟面試官侃半小時MySQL事務,說完原子性、一致性、持久性的實現

 

1)先寫入redo log buffer,在藍色區域。

2)寫入redo log file,可是尚未fsync,這時候是處於黃色的位置,處於系統緩存。

3)調用fsync,真正寫入磁盤。

爲了控制 redo log 的寫入策略,InnoDB 提供了 innodb_flush_log_at_trx_commit 參數,它有三種可能取值:

  • 設置爲 0 的時候,表示每次事務提交時都只是把 redo log 留在 redo log buffer 中 ;
  • 設置爲 1 的時候,表示每次事務提交時都將 redo log 直接持久化到磁盤;
  • 設置爲 2 的時候,表示每次事務提交時都只是把 redo log 寫到 page cache。

binlog的寫入和redo log同樣,也是包括bingo cache和bingo file,一樣跟上面的三色層次相似(固然,binlog是server層的,不是存儲引擎層的),包括log buffer、文件系統page cache、hard disk。

寫入page cache 和 fsync到disk 的時機,是由參數 sync_binlog 控制的:

  • sync_binlog=0 的時候,表示每次提交事務都只 寫入文件系統的page cache,不 fsync;
  • sync_binlog=1 的時候,表示每次提交事務都會執行 fsync;
  • sync_binlog=N(N>1) 的時候,表示每次提交事務都寫入文件系統的page cache,但累積 N 個事務後才 fsync。(若是主機發生異常重啓,會丟失最近 N 個事務的 binlog 日誌)

一般咱們說 MySQL 的「雙 1」配置,指的就是 sync_binlog 和 innodb_flush_log_at_trx_commit 都設置成 1。也就是說,一個事務完整提交前,須要等待兩次刷盤,一次是 redo log(prepare 階段),一次是 binlog。

特別須要區分的是,redo log和binlog的不一樣。這也是常常在面試中可能會問到的兩種日誌的差別。

注意有這麼幾點:

  • 產生位置不一樣。

redo log是innodb的存儲引擎產生的,而binlog是數據庫的server層實現的。換句話說,若是你使用MySQL,換其餘存儲引擎,那麼可能沒有redo log,可是仍是會有binlog。

  • 日誌記錄的內容形式不一樣。

binlog是一種邏輯日誌,記錄對應的SQL語句,而redo log記錄了物理日誌,是針對每一個數據頁的修改。

  • 日誌寫入磁盤時間不一樣。

binlog只有在事務提交後完成一次寫入,對於一個事物而言,在binlog中只有一條記錄。而redo log在事務進行中不斷被寫入,並且是併發寫入的,不是順序寫入的。

跟面試官侃半小時MySQL事務,說完原子性、一致性、持久性的實現

 

  • 保存方式不一樣。

redo log 是循環寫的,空間固定會用完;binlog 是能夠追加寫入的。「追加寫」是指 binlog 文件寫到必定大小後會切換到下一個,並不會覆蓋之前的日誌。

3.原子性的實現

Undo log保證了事務的原子性。

在對數據庫進行修改時,innoDB引擎除了會產生redo log,還會產生undo log。InnoDB實現回滾,靠的是undo log:當事務對數據庫進行修改時,InnoDB會生成對應的undo log;若是事務執行失敗致使事務須要回滾,就利用undo log中的信息將數據回滾到修改以前的樣子。

有人認爲undo log是redo log的逆過程,實際上是不對的。兩個日誌文件其實都能看做是一種對數據的恢復操做,redo log恢復事務致使的數據頁的修改,而undo log可以恢復數據記錄到某個特定的版本。

因此redo log是一種物理日誌(數據頁的修改),而undo log是一種邏輯日誌(數據記錄)。

undo log還要另一個重要做用,就是用於mvcc中,進行多版本控制,也就是實現事務隔離性的基礎,當用戶讀取一行記錄時,若是這個記錄已接被其餘事務佔用,那麼當前事務就能夠經過undo讀取以前的行版本信息,用來實現非鎖定讀取,就是「快照讀」。(事務隔離性的問題,能夠看我上一篇文章 跟面試官侃半小時MySQL事務隔離性,從基本概念深刻到實現 )。

4.一致性的實現

就像一開始在定義的時候介紹的,事務的ACID性質不是徹底正交的,尤爲是一致性,咱們能夠認爲原子性、持久性和隔離性都是爲了實現事務的一致性。

固然,這裏的一致性是指數據庫層面的事務一致性。

若是說你在應用層面作一個操做,給轉帳者扣錢,沒給接收者加錢,那麼這個不一致跟事務的不一致是沒有關係的,須要開發人員本身作業務邏輯一致性的保證。

 

看到這裏了,原創不易,點個關注、點個贊吧,你最好看了~

知識碎片從新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph(歷史文章查閱很是方便)

掃碼關注個人公衆號「阿丸筆記」,第一時間獲取最新更新。同時能夠免費獲取海量Java技術棧電子書、各個大廠面試題。

阿丸筆記

相關文章
相關標籤/搜索