InnoDB 事務(wù)的實(shí)現(xiàn)
事務(wù)四大特性ACID
原子性(A):事務(wù)中的操作要不全部執(zhí)行,要不全部不執(zhí)行寡喝。如果執(zhí)行到一半糙俗,宕機(jī)重啟,已執(zhí)行的一半要回滾回去
一致性(C):各種約束條件拘荡,比如主鍵不能為空臼节、參照完整性
隔離性(I):多個事務(wù)并發(fā)訪問時,事務(wù)之間是隔離的珊皿,一個事務(wù)不應(yīng)該影響其他事務(wù)的運(yùn)行效果
持久性(D):一旦事務(wù)提交了网缝,數(shù)據(jù)不能丟。比如提交了蟋定,但是數(shù)據(jù)沒有刷到磁盤粉臊,宕機(jī)時,要保證將數(shù)據(jù)持久化到磁盤
InnoDB宕機(jī)時也保證數(shù)據(jù)的持久性和原子性驶兜,分為 3 個階段
實(shí)現(xiàn)前提:Checkpoint 機(jī)制
? 基于兩張表:活躍事務(wù)表和臟頁表扼仲,定時將這兩張表進(jìn)行拍快照,存到 redolog 中
-
活躍事務(wù)表:存的是所有沒提交的事務(wù)集合抄淑,每條記錄由 事務(wù) ID + lastLSN(該事務(wù)的最后一條日志的 LSN屠凶,用于進(jìn)行回滾操作)
tx_id lastLSN -
臟頁表:當(dāng)前所有未刷到磁盤上的 Page 集合(包括提交和未提交的事務(wù)),每條記錄由 page_no 和 recoveryLSN(Page 第一次變成臟頁時的 LSN肆资,用于將后面的所有修改都刷磁盤)
page_no recoveryLSN
1. 分析階段:
- 找出哪些數(shù)據(jù)頁是臟頁:通過checkpoint 的臟頁表中的臟頁矗愧,遍歷 redoLog,將遇到的新 Page 加到臟頁集合(可能不是臟頁郑原,但是利用刷 page 的冪等性保障結(jié)果一致)
- 找出哪些事務(wù)沒提交:從 checkpoint 開始唉韭,假如活躍事務(wù)表的未提交事務(wù)的集合為 T1,T2夜涕,遍歷之后的 redoLog,發(fā)現(xiàn)有結(jié)束標(biāo)記的属愤,需要從集合刪除女器,如果是新事務(wù)并且沒有事務(wù)結(jié)束標(biāo)識,就加進(jìn)來住诸,得到最終未提交的事務(wù)
2. 進(jìn)行 Redo
? 從 redolog 中的最后一次 checkpoint 快照驾胆,從臟頁快照中的所有臟頁記錄中得到最小的 recoveryLSN,作為 firstLSN, 遍歷 redoLog只壳,將對于的 Page 全部刷一次磁盤(包括提交和未提交的 Page)俏拱,已提交的Page 重新刷磁盤不會有問題(冪等性:因為 Page 中記錄有個字段pageLSN最后一次修改的LSN,當(dāng)更新時發(fā)現(xiàn)請求的 LSN<=pageLSN,忽略)吼句。
? redo 后,可能會存在需要回滾的Page 數(shù)據(jù)(未提交的數(shù)據(jù))事格,通過 Undo 進(jìn)行恢復(fù)
3. 進(jìn)行 Undo
? 通過分析階段找到未提交的集合惕艳,參考個最后一個日志逆序遍歷,生成逆向的 SQL 語句驹愚,在 redoLog 的尾部進(jìn)行追加远搪。(不存在物理的回滾,全部都是正向的 commit)
總結(jié)
- 通過 undo log + redo log + checkpoint(活躍事務(wù)表和臟表)實(shí)現(xiàn)事務(wù)的 原子性(A)+ 持久性(D)
- 通過 MVCC+ 鎖實(shí)現(xiàn)了事務(wù)的隔離性(I)和并發(fā)性