咱們知道事務有四大特性,原子性、一致性、隔離性與持久性。那麼MySQL中的事務是如何保證這些特性的呢?html
MySQL的存儲引擎InnoDB使用重作日誌保證一致性與持久性,回滾日誌保證原子性,使用各類鎖來保證隔離性。數據庫
防止在發生故障的時間點,尚有髒頁未寫入磁盤,在重啓MySQL服務的時候,根據重作日誌進行重作,從而達到事務的持久性這一特性。 重作日誌由兩部分組成,一是內存中的重作日誌緩存,其是易失的;二是重作日誌文件,其是持久的。重作日誌是物理日誌,記錄的是對於每一個頁的修改。事務開始後Innodb存儲引擎先將重作日誌寫入緩存(innodb_log_buffer)中。而後會經過如下三種方式將innodb日誌緩衝區的日誌刷新到磁盤。緩存
當事務提交時,必須先將該事務的全部日誌寫入到重作日誌文件進行持久化。爲了確保每第二天志都寫入重作日誌文件,在每次將日誌緩衝寫入重作日誌文件後,InnoDB存儲引擎都須要調用一次fsync操做。但這也不是絕對的。用戶能夠經過修改innodb_flush_log_at_trx_commoit參數來控制重作日誌刷新到磁盤的策略。參數默認值爲1,表示事務提交時必須調用一次fsync操做。0表示事務提交時,重作日誌緩存並不當即寫入重作日誌文件,而是隨着Master Thread的間隔進行fsync操做。2表示事務提交時將重作日誌寫入重作日誌文件,但僅寫入文件系統的緩存中,不進行fsync操做。 在InnoDB存儲引擎中。重作日誌都是以512字節進行存儲的,稱之爲重作日誌塊,與磁盤扇區大小一致,這意味着重作日誌的寫入能夠保證原子性,不須要doublewrite技術。併發
事務發生異常須要回滾,這時就須要回滾日誌。回滾日誌不一樣於重作日誌,它是邏輯日誌,對數據庫的修改都邏輯的取消了。當事務回滾時,它實際上作的是與先前相反的工做。對於每一個INSERT,InnoDB存儲引擎都會完成一個DELETE;對於每一個UPDATE,InnoDB存儲引擎都會執行一個相反的UPDATE。線程
事務開始會依照當前版本生成回滾日誌,事務也可使用回滾日誌實現多版本併發控制來保證事務的隔離性。事務提交後並不會立刻刪除回滾日誌,由於可能還有其它事務須要經過回滾日誌來獲得版本信息。因此事務提交時將回滾日誌放入鏈表中,是否能夠刪除由purge線程判斷。日誌
回到剛剛講的重作日誌,未提交的事務和回滾了的事務也會產生重作日誌。InnoDB存儲引擎會重作全部事務包括未提交的事務和回滾了的事務,而後經過回滾日誌回滾那些未提交的事務。使用這種策略須要回滾日誌在重作日誌以前寫入磁盤,使得持久化變得複雜起來。爲了下降複雜度,InnoDB存儲引擎將回滾日誌做數據,記錄回滾日誌的操做也會記錄到重作日誌中。這樣回滾日誌就能夠像數據同樣緩存起來,而不用在重寫日誌以前寫入磁盤了。htm
假設有A、B兩個數據,值分別爲1,2。blog
在MySQL數據庫中還有一種二進制日誌,其用來基於時間點的還原及主從複製。從表面上來看其和重作日誌很是類似,都是記錄了對於數據庫操做的日誌。可是,從本質上來看有着很是大的不一樣。 首先重作日誌是在InnoDB存儲引擎層產生的,而二進制日誌是在MySQL數據庫的上層產生的。其次,兩種日誌記錄的內容形式不一樣。二進制日誌是一種邏輯日誌,其記錄的是對應的SQL語句。而重作日誌是物理日誌,記錄的是每一個頁的修改。此外,兩種日誌記錄寫入磁盤的時間點不一樣,二進制日誌只在事務提交完成後進行一次寫入,重作日誌在事務進行時不斷地寫入。事務
@COPY內存