水稻: 菜瓜,聽說最近你在復習MySQL方面的知識,想請教一下MySQL的事務?
菜瓜:嗯,最近剛剛看到。事務指的是MySQL中不可拆分的業務單元,具有ACID的屬性。
水稻: ACID我知道啊,但是不太懂他的實現,你能說和我聊聊事務在數據庫底層是怎么實現的嗎?
菜瓜:據我了解,不同的特性底層的實現不一樣,主要依賴兩種日志和鎖來實現
- 先說持久性:我們知道數據的操作會先在內存中完成,那么事務提交后如何保證一定能持久化到磁盤呢
- redo log: 事務在提交前對數據的修改會先寫到redo log 中,如果返回事務已提交成功,那么表示redo log已經記錄完成。redo log 也有緩沖區,redo log的內存緩沖區大小和磁盤扇區的大小512字節一致,不會出現掉電易失的情況。另外redo log記錄的是物理變化,體積很小,且redo log 寫磁盤是順序IO,極快~絲滑
- redo log 和binlog區別:一個是用於做持久化,另一個用作數據恢復和復制
- 原子性,指的是被事務包裹的一組操作要么全部成功,要么全部失敗。不會存在執行了一部分,另一部分不執行的情況
- undo log: MySQL使用undo log實現操作回滾。事務開啟后執行的命令都會有一條對應反向的邏輯日志計入undo日志文件中(譬如insert 就會有一條delete)。undo log的持久化會被記錄在redo log中(利用redo log 速度快的特性)。一旦發生錯誤或者回滾的時候,利用undo就可以操作回去
水稻: 那還有一致性和隔離性呢?
菜瓜:一致性和隔離性可以放在一起說,隔離級別的選擇就是一致性和隔離性的權衡
- 實現多個事務之間的隔離。一種是鎖,另一種是mvcc機制。
水稻:鎖我知道,mvcc是什么?
菜瓜:我們把數據庫的讀操作分為兩類,一是當前讀,使用鎖機制;一是快照讀,使用mvcc
- 當前讀
- 數據的修改操作(insert update delete)和查詢時顯示加鎖 select(查詢條件后加上 lock in share mode & for update)
- 會鎖住要讀取的數據以保障數據的一致
- 快照讀 使用的是mvcc機制,就是多版本並發控制。
- 除當前讀之外,普通的select查詢為快照讀,顧名思義,就是讀取的是一個快照版本,以隔離多個事務之間的數據
水稻:能不能仔細說說這個mvcc
菜瓜:可以,它的實現還是依賴undo log來做的
- 在RR RC兩種級別下使用。其他兩種不需要實現隔離
- 你肯定聽說過mysql在RR級別下解決了幻讀問題,就是依賴這個來做的
- 簡單來說就是,MySQL維護了一個記錄活躍事務id的列表readview
- undo log是怎么記錄的呢。舉個栗子🌰
- innodb的表中存在三個額外的隱藏字段,分別是編輯該條記錄的事務id,更改前的undo log的回滾指針,還有一個對我們這個分析不太重要
- 如果有事務對該記錄做了變更,事務id會更新,同時undo log里面會產生新記錄,回滾指針字段指向最新的undo log鏈
- 通過比較當前事務id和readview中其他事務的id大小來決定自己讀取的數據是哪個版本的undo log記錄
- 如果當前事務id比readview中的都小,就說明該條記錄沒有被其他事務更改。直接讀取
- 如果當前事務id比readview中的都大,沿着undo log鏈能找到最小事務id指向的undo log,該數據為穩定數據
- RR級別下利用該機制避免了幻讀
- RC級別下每次都會讀取數據的最新記錄
總結:
- 事務的持久性和原子性由Redo log和Undo log實現
- 隔離性和一致性的權衡由鎖機制和MVCC實現
部分內容為自己猜想,如有錯誤,歡迎指正!
參考文章
- MySql-Undo及Redo詳解 https://blog.csdn.net/aaa821/article/details/80645242
- MySql MVCC 多版本並發控制 https://www.cnblogs.com/paulwang92115/p/12189487.html