漫談MySql中的事務

來源:互聯網
上載者:User

標籤:

 最近一直在做訂單類的項目,使用了事務。我們的資料庫選用的是MySql,儲存引擎選用innoDB,innoDB對事務有著良好的支援。這篇文章我們一起來扒一扒事務相關的知識。

為什麼要有事務?

        事務廣泛的運用於訂單系統、銀行系統等多種情境。如果有以下一個情境:A使用者和B使用者是銀行的儲戶。現在A要給B轉賬500元。那麼需要做以下幾件事:

            1. 檢查A的賬戶餘額>500元;

            2. A賬戶扣除500元;

            3. B賬戶增加500元;

        正常的流程走下來,A賬戶扣了500,B賬戶加了500,皆大歡喜。那如果A賬戶扣了錢之後,系統出故障了呢?A白白損失了500,而B也沒有收到本該屬於他的500。以上的案例中,隱藏著一個前提條件:A扣錢和B加錢,要麼同時成功,要麼同時失敗。事務的需求就在於此。

事務是什嗎?

        與其給事務定義,不如說一說事務的特性。眾所周知,事務需要滿足ACID四個特性。

            1. A(atomicity) 原子性。一個事務的執行被視為一個不可分割的最小單元。事務裡面的操作,要麼全部成功執行,要麼全部失敗復原,不可以只執行其中的一部分。

            2. C(consistency) 一致性。一個事務的執行不應該破壞資料庫的完整性條件約束。如果上述例子中第2個操作執行後系統崩潰,保證A和B的金錢總計是不會變的。

            3. I(isolation) 隔離性。通常來說,事務之間的行為不應該互相影響。然而實際情況中,事務相互影響的程度受到隔離等級的影響。文章後面會詳述。

            4. D(durability) 持久性。事務提交之後,需要將提交的事務持久化到磁碟。即使系統崩潰,提交的資料也不應該丟失。

事務的四種隔離等級

        前文中提到,事務的隔離性受到隔離等級的影響。那麼事務的隔離等級是什麼呢?事務的隔離等級可以認為是事務的"自私"程度,它定義了事務之間的可見度。隔離等級分為以下幾種:

          1.READ UNCOMMITTED(未提交讀)。在RU的隔離等級下,事務A對資料做的修改,即使沒有提交,對於事務B來說也是可見的,這種問題叫髒讀。這是隔離程度較低的一種隔離等級,在實際運用中會引起很多問題,因此一般不常用。

          2.READ COMMITTED(提交讀)。在RC的隔離等級下,不會出現髒讀的問題。事務A對資料做的修改,提交之後會對事務B可見,舉例,事務B開啟時讀到資料1,接下來事務A開啟,把這個資料改成2,提交,B再次讀取這個資料,會讀到最新的資料2。在RC的隔離等級下,會出現不可重複讀取的問題。這個隔離等級是許多資料庫的預設隔離等級。

          3.REPEATABLE READ(可重複讀)。在RR的隔離等級下,不會出現不可重複讀取的問題。事務A對資料做的修改,提交之後,對於先於事務A開啟的事務是不可見的。舉例,事務B開啟時讀到資料1,接下來事務A開啟,把這個資料改成2,提交,B再次讀取這個資料,仍然只能讀到1。在RR的隔離等級下,會出現幻讀的問題。幻讀的意思是,當某個事務在讀取某個範圍內的值的時候,另外一個事務在這個範圍插入入了新記錄,那麼之前的事務再次讀取這個範圍的值,會讀取到新插入的資料。Mysql預設的隔離等級是RR,然而mysql的innoDB引擎間隙鎖成功解決了幻讀的問題。

          4.SERIALIZABLE(可序列化)。可序列化是最高的隔離等級。這種隔離等級強制要求所有事物串列執行,在這種隔離等級下,讀取的每行資料都加鎖,會導致大量的鎖徵用問題,效能最差。

       為了協助理解四種隔離等級,這裡舉個例子。1,事務A和事務B先後開啟,並對資料1進行多次更新。四個小人在不同的時刻開啟事務,可能看到資料1的哪些值呢?

           

                                                            圖1

        第一個小人,可能讀到1-20之間的任何一個。因為未提交讀的隔離等級下,其他事務對資料的修改也是對當前事務可見的。第二個小人可能讀到1,10和20,他只能讀到其他事務已經提交了的資料。第三個小人讀到的資料去決於自身事務開啟的時間點。在事務開啟時,讀到的是多少,那麼在事務提交之前讀到的值就是多少。第四個小人,只有在A end 到B start之間開啟,才有可能讀到資料,而在事務A和事務B執行的期間是讀不到資料的。因為第四小人讀資料是需要加鎖的,事務A和B執行期間,會佔用資料的寫鎖,導致第四個小人等待鎖。

        圖2羅列了不同隔離等級所面對的問題。

        

                                                       圖2

        很顯然,隔離等級越高,它所帶來的資源消耗也就越大(鎖),因此它的並發效能越低。準確的說,在可序列化的隔離等級下,是沒有並發的。

                

                                                         圖3

MySql中的事務

        事務的實現是基於資料庫的儲存引擎。不同的儲存引擎對事務的支援程度不一樣。mysql中支援事務的儲存引擎有innoDB和NDB。innoDB是mysql預設的儲存引擎,預設的隔離等級是RR,並且在RR的隔離等級下更進一步,通過多版本並發控制(MVCC,Multiversion Concurrency Control )解決不可重複讀取問題,加上間隙鎖(也就是並發控制)解決幻讀問題。因此innoDB的RR隔離等級其實實現了序列化層級的效果,而且保留了比較好的並發效能。

       事務的隔離性是通過鎖實現,而事務的原子性、一致性和持久性則是通過交易記錄實現。說到交易記錄,不得不說的就是redo和undo。

     1.redo log

       在innoDB的儲存引擎中,交易記錄通過重做(redo)日誌和innoDB儲存引擎的日誌緩衝(InnoDB Log Buffer)實現。事務開啟時,事務中的操作,都會先寫入儲存引擎的日誌緩衝中,在事務提交之前,這些緩衝的日誌都需要提前重新整理到磁碟上持久化,這就是DBA們口中常說的“日誌先行”(Write-Ahead Logging)。當事務提交之後,在Buffer Pool中映射的資料檔案才會慢慢重新整理到磁碟。此時如果資料庫崩潰或者宕機,那麼當系統重啟進行恢複時,就可以根據redo log中記錄的日誌,把資料庫恢複到崩潰前的一個狀態。未完成的事務,可以繼續提交,也可以選擇復原,這基於恢複的策略而定。

        在系統啟動的時候,就已經為redo log分配了一塊連續的儲存空間,以順序追加的方式記錄Redo Log,通過順序IO來改善效能。所有的事務共用redo log的儲存空間,它們的Redo Log按語句的執行順序,依次交替的記錄在一起。如下一個簡單樣本:

        記錄1:<trx1, insert...>

        記錄2:<trx2, delete...>

        記錄3:<trx3, update...>

        記錄4:<trx1, update...>

        記錄5:<trx3, insert...>

      2.undo log

        undo log主要為事務的復原服務。在事務執行的過程中,除了記錄redo log,還會記錄一定量的undo log。undo log記錄了資料在每個操作前的狀態,如果事務執行過程中需要復原,就可以根據undo log進行復原操作。單個事務的復原,只會復原當前事務做的操作,並不會影響到其他的事務做的操作。

        以下是undo+redo事務的簡化過程

        假設有2個數值,分別為A和B,值為1,2

        1. start transaction;

        2. 記錄 A=1 到undo log;

        3. update A = 3;

        4. 記錄 A=3 到redo log;

        5. 記錄 B=2 到undo log;

        6. update B = 4;

        7. 記錄B = 4 到redo log;

        8. 將redo log重新整理到磁碟

        9. commit

        在1-8的任意一步系統宕機,事務未提交,該事務就不會對磁碟上的資料做任何影響。如果在8-9之間宕機,恢複之後可以選擇復原,也可以選擇繼續完成事務提交,因為此時redo log已經持久化。若在9之後系統宕機,記憶體映射中變更的資料還來不及刷回磁碟,那麼系統復原之後,可以根據redo log把資料刷回磁碟。

        所以,redo log其實保障的是事務的持久性和一致性,而undo log則保障了事務的原子性。

分散式交易

        分散式交易的實現方式有很多,既可以採用innoDB提供的原生的事務支援,也可以採用訊息佇列來實現分散式交易的最終一致性。這裡我們主要聊一下innoDB對分散式交易的支援。

        

        ,mysql的分散式交易模型。模型中分三塊:應用程式(AP)、資源管理員(RM)、交易管理員(TM)。

        應用程式定義了事務的邊界,指定需要做哪些事務;

        資源管理員提供了訪問事務的方法,通常一個資料庫就是一個資源管理員;

        交易管理員協調參與了全域事務中的各個事務。

        分散式交易採用兩段式提交(two-phase commit)的方式。第一階段所有的事務節點開始準備,告訴交易管理員ready。第二階段交易管理員告訴每個節點是commit還是rollback。如果有一個節點失敗,就需要全域的節點全部rollback,以此保障事務的原子性。

總結

        什麼時候需要使用事務呢?我想,只要業務中需要滿足ACID的情境,都需要事務的支援。尤其在訂單系統、銀行系統中,事務是不可或缺的。這篇文章主要介紹了事務的特性,以及mysql innoDB對事務的支援。事務相關的知識遠不止文中所說,本文僅作拋磚引玉,不足之處還望讀者多多見諒。

 

參考文獻:

 《高效能mysql第三版》

 《mysql技術內幕 innoDB儲存引擎》

漫談MySql中的事務

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.