mysql事物原理(一)-undo log、redo log、MVCC


redo log

redo log叫做重做日志.用於解決數據庫事物提交 還未刷入磁盤,服務器down機導致的數據丟失的問題。

InnoDB作為MySQL的存儲引擎,數據存儲在磁盤中,如果每次讀寫數據都要操作磁盤IO效率會很低,為此InnoDB提供了緩存(Buffer Pool),Buffer Pool中包含了磁盤中部分數據頁的映射,作為訪問數據庫的緩沖:當從數據庫讀取數據時,會首先從Buffer Pool中讀取,如果Buffer Pool中沒有,則從磁盤讀取后放入Buffer Pool;當向數據庫寫入數據時,會首先寫入Buffer Pool,Buffer Pool中修改的數據會定期刷新到磁盤中(刷臟)

Buffer Pool的使用大大提高了讀寫數據的效率,但是也帶了新的問題:如果MySQL宕機,而此時Buffer Pool中修改的數據還沒有刷新到磁盤,就會導致數據的丟失,事務的持久性無法保證。

於是,redo log被引入來解決這個問題:當數據修改時,除了修改Buffer Pool中的數據,還會在redo log記錄這次操作;當事務提交時,會調用fsync接口對redo log進行刷盤。如果MySQL宕機,重啟時可以讀取redo log中的數據,對數據庫進行恢復。redo log采用的是WAL(Write-ahead logging,預寫式日志),所有修改先寫入日志,再更新到Buffer Pool,保證了數據不會因MySQL宕機而丟失,從而滿足了持久性要求。

既然redo log也需要在事務提交時將日志寫入磁盤,為什么它比直接將Buffer Pool中修改的數據寫入磁盤(即刷臟)要快呢?主要有以下兩方面的原因:

(1)刷臟是隨機IO,因為每次修改的數據位置隨機,但寫redo log是追加操作,屬於順序IO。

(2)刷臟是以數據頁(Page)為單位的,MySQL默認頁大小是16KB,一個Page上一個小修改都要整頁寫入;而redo log中只包含真正需要寫入的部分,無效IO大大減少。

 

undo log

undo log的2個主要作用是實現MVCC和事物回滾

當 delete 一條記錄時,undo log 中會記錄一條對應的 insert 記錄,反之亦然,當 update 一條記錄時,它記錄一條對應相反的 update 記錄,如果 update 的是主鍵,則是對先刪除后插入的兩個事件的反向邏輯操作的記錄。

 

 

 在事物回滾時就會反向讀取相應內容進行回滾,也可以根據undo log讀取到被修改后數據的原值

MVCC的實現原理

MVCC的實現主要利用到了數據庫隱式字段和undo log、ReadView

MVCC的好處主要實現思想是通過數據多版本來做到讀寫分離。從而實現不加鎖讀進而做到讀寫並行。

MVCC結構

 

Column1 Column2位數據格式

DB_TRX_ID(隱式字段) 最近一次修改的事物id(注:事物id都是遞增的)

DB_ROLL_PTR(隱式字段)  回滾日志 指向undo log

DB_ROW_ID(隱式字段) 自增ID如果數據庫表沒有指定主鍵 則默認以此作為聚簇索引

undo log 版本鏈

事物A id=1的事物將小明改為小張

 

 

 

 

事物B id=2的事物將age改為30

ReadView

read view(快照)是基於undo log實現的可以實現不加鎖的情況下並發讀 讀已提交和可重復讀都是通過ReadView實現

快照讀和當前讀

詳情可可以看《快照讀和當前讀》

數據結構

m_ids:當前有哪些事務正在執行,且還沒有提交,這些事務的 id 就會存在這里

min_trx_id:是指 m_ids 里最小的值

max_trx_id:下一個要生成的事物id,因為事物id是遞增的 肯定比當前所有事物id要大

creator_trx_id: 創建read view的事物id

RE隔離級別讀已提交實現原理

圖1.事物A id等於1將數據修改並提交

 

圖2.事物B執行查詢

 

1.事物B執行快照讀(注:RR隔離級別只會生成一次快照 RE隔離級別每次都會生成新的快照

2.讀取到數據通過數據隱藏列DB_TRX_ID值1跟min_trx_id做比較, DB_TRX_ID<min_trx_id 說明最近修改此數據的事物已經提交則可以正常讀取 column1=小張   column2=32

圖3

1.事物C將colunm2=32 改為16事物並未提交

2.事物B執行select讀取數據通過DB_TRX_ID與min_trx_id做比較 發現比最小事物id大。表示有可能讀到的。再將DB_TRX_ID=4在min_ids進行查找 成功找到。發現事物還未提交

3.通過undolog鏈跟往上找(通步驟2一樣的查找方式)成功查到 colunm1=小明 colunm2=32的數據 成功讀取  

圖4

 

1.又回到了圖一。事物C提交事物后。事物B進行查詢重新生成快照(RE隔離級別每次都會生成新的快照) 

2.這個時候m_ids里面已經沒有4了。數據行DB_TRX_ID>min_trx_id 同時又不在m_ids里面存在表示已經提交了直接讀取

RR可重復讀實現原理

 

流程都一樣 唯一不同的是只會生成一次快照,就算事物C提交了  m_ids[2,4] 還是有2和4 所以讀到的數據還是小明 32

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM