一篇了解全MVCC( 二 )


1)可見性算法將要被修改的數據的最新記錄中的DB_TRX_ID(當前事務id)取出來,與系統此刻其他活躍事務的id去對比,如果DB_TRX_ID跟Read View的屬性做了比較,不符合可見性,那么就通過DB_ROLL_PTR回滾指針去取出undolog中的DB_TRX_ID做比較,即遍歷鏈表中的DB_TRX_ID,直到找到滿足條件的DB_TRX_ID , 這個DB_TRX_ID所在的舊記錄就是當前事務能看到的數據 。
2)可見性規則首先要知道Read View中的三個全局屬性:

  • trx_list:一個數值列表,用來維護Read View生成時刻系統正活躍的事務ID(1,2,3)
  • up_limit_id:記錄trx_list列表中事務ID最小的ID(1)
  • low_limit_id:Read View生成時,系統即將分配的下一個事務ID(4)
具體的比較規則如下:
  • 首先比較DB_TRX_ID < up_limit_id如果小于,則當前事務能看到DB_TRX_ID所在的記錄如果大于等于,則進入下一個判斷
  • 接下來判斷DB_TRX_ID >= low_limit_id如果大于等于,則代表DB_TRX_ID所在的記錄在Read View生成后才出現的,那么對于當前事務不可見如果小于 , 則進入下一步判斷
  • 判斷DB_TRX_ID是否在活躍事務中,trx_list包含DB_TRX_ID如果包含,則代表在Read View生成的時候,這個事務還是活躍狀態,未commit的數據,當前事務也是看不到如果不包含,則說明這個事務在Read View生成之前就已經開始commit,那么修改的結果是能夠看見的
流程圖如下:
一篇了解全MVCC

文章插圖
總結:兩種情況可見
  • DB_TRX_ID < up_limit_id
  • DB_TRX_ID不在trx_list范圍內 , 且小于low_limit_id
四、整個流程假設有四個事務同時在執行,如下圖所示:
事務1事務2事務3事務4事務開始事務開始事務開始事務開始………修改且已提交進行中快照讀進行中 ……… 從上述表格中,我們可以看到,當事務2對某行數據執行了快照讀,數據庫為該行數據生成一個Read View視圖,可以看到事務1和事務3還在活躍狀態,事務4在事務2快照讀的前一刻提交了更新,所以在Read View中記錄了系統當前活躍事務1,3,維護在一個列表中 。同時可以看到up_limit_id的值為1,而low_limit_id為5 , 如下圖所示:
一篇了解全MVCC

文章插圖
在上述的例子中 , 只有事務4修改過該行記錄,并且在事務2進行快照讀前,就提交了事務,所以該行當前數據的undolog如下所示:
一篇了解全MVCC

文章插圖
當事務2在快照讀該行記錄時,會拿著該行記錄的DB_TRX_ID去跟up_limit_id、lower_limit_id和活躍事務列表進行比較,從而判讀事務2能看到該行記錄的版本是哪個 。具體流程如下:
  • 拿該行記錄的事務ID(4)去跟Read View中的up_limit_id(1)相比較 , 判斷是否小于 , 通過對比發現不小于,所以不符合條件
  • 繼續判斷4是否大于等于low_limit_id(5),通過比較發現也不大于,所以不符合條件
  • 判斷事務4是否處理trx_list列表中,發現不在列表中,那么符合可見性條件
所以事務4修改后提交的最新結果對事務2的快照是可見的,因此事務2讀取到的最新數據記錄是事務4所提交的版本,而事務4提交的版本也是全局角度的最新版本 。
五、拓展1、當前讀讀取的是最新版本的記錄,讀取時還要保證其它并發事務不能修改當前記錄,會對讀取的記錄進行加鎖
  • 共享鎖:select lock in share mode
  • 排它鎖:select for update 、update、 insert 、delete
2、快照/普通讀1)概念像不加鎖的select操作,就是快照讀,即非阻塞讀
2)為什么會出現快照讀?是基于提高并發性能的考慮,快照讀是基于多版本并發控制,即MVCC,可以認為MVCC是行鎖的一個變種,但它在很多情況下,避免了加鎖操作,降低了開銷;
3)存在問題
  • 基于多版本,讀到的并不一定是數據的最新版本,可能是之前的歷史版本
  • 串行級別下的快照讀會退化成當前讀
3、RC、RR級別下的InnoDB快照讀有什么不同因為Read View生成時機的不同,從而造成RC、RR級別下快照讀的結果的不同