一般是通過鎖機制,解決掉不可重複讀和幻讀的問題。是不是可以通過樂觀鎖的問題去解決不可重複讀和幻讀的問題,MySQL 採用的是 MVCC 機制來解決髒讀、不可重複讀的問題。
MVCC 英文全稱是 Muitiversion Concurrency Control,多版本並發控制技術,原理是通過數據行的多個版本管理實現資料庫的並發控制,通過保存數據的歷史版本,可以通過比較版本號決定數據是否顯示,讀取數據的時候不需要加鎖保證事務的隔離效果。
MVCC 是如何解決髒讀的?MVCC 解決了一致性讀問題,當我們讀取某個資料庫在時間點的快照時,只能看到時間點之前提交更新的結果,不能看到時間點之後事務提交的更新結果。這樣就避免了髒讀問題。
MVCC 是如何解決不可重複讀的?
在說如何解決不可重複讀之前,先談談 MVCC 的實現原理。
快照讀
快照讀,讀取的是快照數據,一般不加鎖的 select 查詢都是快照讀。
select * from player where ...
當前讀
當前讀就是讀的最新數據,而不是歷史數據,加鎖的 select,或者對數據進行增刪改都會讀取當前最新數據。
SELECT * FROM player LOCK IN SHARE MODE;
SELECT FROM player FOR UPDATE;
INSERT INTO player values ...
DELETE FROM player WHERE ...
UPDATE player SET ...
MVCC 是基於 Read View + 活躍事務表實現的。
行記錄快照模型數據表中的一行記錄實際上有多個版本,每個版本有自己的事務 ID(row_trx_id)每次需要讀取那個版本數據的時候,是通過當前版本,加 Undo Log 中存儲的快照鍊表得到那個版本真實數據。
行記錄快照是保存在 Undo Log 中,並且行記錄快照是通過鍊表串聯起來,每個快照都保存了 trx_id (事務 ID),如果要找到歷史快照,只需要遍歷回滾指針進行查找。
Read View會有這麼一個問題:一個事務開啟,這個事務要查詢數據,需要讀取哪個版本的行記錄呢?Read View 就是來解決這個問題的,簡單的說 Read View 是可以幫助我們解決可見性問題的。
ReadView 中保存了當前活躍的事務列表。通過比較事務版本,可以判斷當前行數據版本是不是對當前事務可見。
Read View 模型
如果當前行記錄版本是 trx_id < 活躍的最小事務 ID (up_limit_id),說明行記錄在這些活躍的事務創建前就已經提交,這個行記錄對當前事務是可見的。
如果當前行記錄事務版本 trx_id > 活躍的最大事務 ID (low_limit_id) 說明,這個行記錄是在事務後創建的,這個行記錄對當前事務不可見。
如果 up_limit_id < trx_id < low_limit_id,則有如下情況:
若 row trx_id 在數組 trx_ids 中,表示這個版本是由還沒提交的事務生成的,不可見。
若 row trx_id 不在數組 trx_ids 中,表示這個版本是已經提交了的事務生成的,可見。