MVCC如何在RR上解決幻讀


一、InnoDB如何解決幻讀

  • 幻讀:在InnoDB的可重復度隔離級別下,使用當前讀,一個事務前后兩次查詢同一個范圍,后一次查詢會看到期間新插入的行;
  • 幻讀的影響:會導致一個事務中先產生的鎖,無法鎖住后加入的行,會產生數據一致性問題;
  • 產生幻讀的原因:行鎖只能鎖住一行,不能避免新插入的記錄;
  • 解決幻讀:在兩行記錄之間加上間隙鎖,阻止新紀錄的插入,與間隙鎖產生沖突的只有“往這個間隙插入記錄”這個操作;
  • 同時添加間隙鎖與行鎖稱為Next-key lock,注意間隙鎖只有在InnoDB的可重復度隔離級別下生效;
  • MVCC只實現讀取已提交和可重復讀,InnoDB在可重復度的隔離級別下,使用MVCC+Next-key lock解決幻讀;

二、多版本並發控制MVCC

1.基本思想

  • MVCC是InnoDB實現隔離級別的一種方式,用於實現讀取已提交和可重復讀兩種隔離級別;
  • 對於讀取未提交,直接讀取最新版本的數據;
  • 對於串行化,使用加鎖的方式訪問記錄;
  • 大多數事務型存儲引擎實現都不是簡單的行鎖,基於並發性的考慮,一般會同時實現多版本並發控制(MVCC)處理讀寫沖突;
  • MVCC是樂觀鎖的一種實現,是通過保存數據在某一個時間點的快照實現的,寫操作更新最新的版本,讀操作讀取舊版本;
  • MVCC中事務的修改操作(增刪改)會為行記錄新增一個版本快照,並把當前事務id寫入trx_id;

2.版本號

  • 系統版本號sys_id:每開始一個新的事務,系統版本號遞增;
  • 在InnoDB中,聚簇索引記錄中包含兩個隱藏列:
    • trx_id:對記錄進行改動時,trx_id會記錄當前事務id,也就是當前系統版本號;
    • roll_pointer:對記錄進行改動,會把舊版本記錄寫入undo日志,roll_pointer指向修改之前的版本;
  • 對同一條記錄的更新,會把舊值放到一條undo日志中,作為一個舊版本的記錄,多次更新之后這些版本會被roll_pointer連接成一個鏈表,稱之為版本鏈

3.版本讀取

  • 對於讀取已提交可重復讀,就會用到版本鏈,關鍵在於怎么判斷版本鏈中哪個版本對當前事務可見;
  • 使用ReadView(快照),ReadView是一個包含當前已經開始但是沒有提交的事務的列表,記錄每個事務的事務id,記最小事務id為min_id,最大事務id為max_id;
  • 版本比較規則:
  1. 如果記錄版本的trx_id小於min_id,說明這個記錄版本是已經被提交過的,對其他事務可見;
  2. 如果記錄版本的trx_id大於max_id,說明這個記錄版本是ReadView生成之后發生的,不能訪問;
  3. 如果記錄版本的trx_id在min_id和max_id之間,判斷trx_id是否在ReadView中:
  • 如果在ReadView中,說明事務還未提交,該記錄版本不可訪問;
  • 如果不在ReadView中,說明該事務已經提交,該記錄版本可以訪問;
  • 如果當前記錄版本不可讀,就根據回滾指針roll_pointer找到舊版本的記錄再進行判斷;
  • 對於讀取已提交,每次查詢都會生成一個新的ReadView;
  • 對於可重復度,一個事務在第一次SELECT的時候生成一個ReadView,之后的查詢復用這個ReadView;

4.快照讀與當前讀

  • 快照讀:MVCC中的SELECT操作是讀取快照中的數據,不需要進行加鎖;
  • 當前讀:MVCC中修改數據的操作(增刪改)需要進行加鎖操作,從而讀取最新的數據;

5.例子

  • 假設當前有一個事務id為100的事務A,修改一個記錄的name字段為name2,產生一個版本快照,因此有這樣的版本鏈:
  • 假設事務A還沒有提交,此時事務B進行SELECT,事務id為120,查詢id為1的記錄(記為第一次查詢),此時生成ReadView為[100,120],根據版本讀取規則,先找到trx_id為100的記錄版本,發現不可讀,於是通過回滾指針找到trx_id為60的記錄,讀取成功;
  • 當事務A提交之后,事務B再次進行SELECT查詢id為1的記錄(第二次查詢),在讀取已提交和可重復讀兩種隔離級別下有不同的情況:
    • 如果是讀取已提交,則會創建一個新的ReadView為[120],此時讀取trx_id為100的記錄成功,也就是讀取到了在事務期間提交的數據;
    • 如果是可重復讀,則會使用第一次查詢時的ReadView為[100,120],此時讀取的是trx_id為60的記錄,從而實現了可重復度;

 

菜雞的小疑惑:
三級封鎖協議不是可以解決臟讀和不可重復度的問題嗎,為什么要用MVCC來實現,是性能更好嗎?
轉自:https://zhuanlan.zhihu.com/p/180350695


免責聲明!

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



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