MVVC(多版本並發控制)


1、MVCC

​   MVCC,全稱Multi-Version Concurrency Control,即多版本並發控制。MVCC是一種並發控制的方法,一般在數據庫管理系統中,實現對數據庫的並發訪問,在編程語言中實現事務內存。MVCC在MySQL InnoDB中的實現主要是為了提高數據庫並發性能,用更好的方式去處理讀寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞並發讀

2、當前讀

​  select lock in share mode(共享鎖)、select for update 、 update、insert 、delete(排他鎖)這些操作都是一種當前讀,為什么叫當前讀?就是它讀取的是記錄的最新版本,讀取時還要保證其他並發事務不能修改當前記錄,會對讀取的記錄進行加鎖

3、快照讀

​  不加鎖的select操作就是快照讀,即不加鎖的非阻塞讀,提高數據庫的並發查詢能力;快照讀的前提是隔離級別不是串行級別,串行級別下的快照讀會退化成當前讀;之所以出現快照讀的情況,是基於提高並發性能的考慮,快照讀的實現是基於多版本並發控制,即MVCC,可以認為MVCC是行鎖的一個變種,但它在很多情況下,避免了加鎖操作,降低了開銷;既然是基於多版本,即快照讀可能讀到的並不一定是數據的最新版本,而有可能是之前的歷史版本

4、當前讀、快照讀、MVCC關系

​  MVCC多版本並發控制指的是維持一個數據的多個版本,使得讀寫操作沒有沖突,快照讀是MySQL為實現MVCC的一個非阻塞讀功能。MVCC模塊在MySQL中的具體實現是由三個隱式字段,undo日志、read view三個組件來實現的

5、MVCC解決的問題

​   數據庫並發場景有三種,分別為:

​   1、讀讀:不存在任何問題,也不需要並發控制

​   2、讀寫:有線程安全問題,可能會造成事務隔離性問題,可能遇到臟讀、幻讀、不可重復讀

​   3、寫寫:有線程安全問題,可能存在更新丟失問題

​  MVCC是一種用來解決讀寫沖突的無鎖並發控制,也就是為事務分配單項增長的時間戳,為每個修改保存一個版本,版本與事務時間戳關聯,讀操作只讀該事務開始前的數據庫的快照,所以MVCC可以為數據庫解決以下問題:

​     1、在並發讀寫數據庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數據庫並發讀寫的性能

​     2、解決臟讀、幻讀、不可重復讀等事務隔離問題,但是不能解決更新丟失問題

6、MVCC實現原理

​   MVCC的實現原理主要依賴於記錄中的三個隱藏字段,undolog,read view來實現的

​   隱藏字段每行記錄除了我們自定義的字段外,還有數據庫隱式定義的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID等字段

​     DB_TRX_ID:6字節,最近修改事務id,記錄創建這條記錄或者最后一次修改該記錄的事務id

​     DB_ROLL_PTR:7字節,回滾指針,指向這條記錄的上一個版本,用於配合undolog,指向上一個舊版本

​     DB_ROW_ID:6字節,隱藏的主鍵,如果數據表沒有主鍵,那么innodb會自動生成一個6字節的row_id,

​   undo log回滾日志,表示在進行insert,delete,update操作的時候產生的方便回滾的日志

    當進行insert操作的時候,產生的undolog只在事務回滾的時候需要,並且在事務提交之后可以被立刻丟棄;

    當進行update和delete操作的時候,產生的undolog不僅僅在事務回滾的時候需要,在快照讀的時候也需要,所以不能隨便刪除,只有在快照讀或事務回滾不涉及該日志時,對應的日志才會被purge線程統一清除(當數據發生更新和刪除操作的時候都只是設置一下老記錄的deletedbit,並不是真正的將過時的記錄刪除,因為為了節省磁盤空間,innodb有專門的purge線程來清除deletedbit為true的記錄,如果某個記錄的deleted_id為true,並且DB_TRXI_D相對於purge線程的read view 可見,那么這條記錄一定時可以被清除的);

    不同事務或者相同事務的對同一記錄的修改,會導致該記錄的undolog生成一條記錄版本線性表,即鏈表,undolog的鏈首就是最新的舊記錄,鏈尾就是最早的舊記錄

​   Read View:Read View是事務進行快照讀操作的時候生產的讀視圖,在該事務執行快照讀的那一刻,會生成一個數據系統當前的快照,記錄並維護系統當前活躍事務的id,事務的id值是遞增的

    其實Read View的最大作用是用來做可見性判斷的,也就是說當某個事務在執行快照讀的時候,對該記錄創建一個Read View的視圖,把它當作條件去判斷當前事務能夠看到哪個版本的數據,有可能讀取到的是最新的數據,也有可能讀取的是當前行記錄的undolog中某個版本的數據

​    Read View遵循的可見性算法主要是將要被修改的數據的最新記錄中的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所在的舊記錄就是當前事務能看到的最新老版本數據。Read View的可見性規則如下所示,首先要知道Read View中的三個全局屬性:

​       trx_list:一個數值列表,用來維護Read View生成時刻系統正活躍的事務ID

​       uplimitid:記錄trx_list列表中事務ID最小的ID

​       lowlimitid:Read View生成時刻系統尚未分配的下一個事務ID

​     具體的比較規則如下:

​     1、首先比較DB_TRX_ID < uplimitid,如果小於,則當前事務能看到DB_TRX_ID所在的記錄,如果大於等於進入下一個判斷

​     2、接下來判斷DB_TRX_ID >= lowlimitid,如果大於等於則代表DB_TRX_ID所在的記錄在Read View生成后才出現的,那么對於當前事務肯定不可見,如果小於,則進入下一步判斷

​     3、判斷DB_TRX_ID是否在活躍事務中,如果在,則代表在Read View生成時刻,這個事務還是活躍狀態,還沒有commit,修改的數據,當前事務也是看不到,如果不在,則說明這個事務在Read View生成之前就已經開始commit,那么修改的結果是能夠看見的

7、RC、RR級別下的InnoDB快照讀有什么不同

​   因為Read View生成時機的不同,從而造成RC、RR級別下快照讀的結果的不同

​   1、在RR級別下的某個事務的對某條記錄的第一次快照讀會創建一個快照即Read View,將當前系統活躍的其他事務記錄起來,此后在調用快照讀的時候,還是使用的是同一個Read View,所以只要當前事務在其他事務提交更新之前使用過快照讀,那么之后的快照讀使用的都是同一個Read View,所以對之后的修改不可見

​   2、在RR級別下,快照讀生成Read View時,Read View會記錄此時所有其他活動和事務的快照,這些事務的修改對於當前事務都是不可見的,而早於Read View創建的事務所做的修改均是可見

​   3、在RC級別下,事務中,每次快照讀都會新生成一個快照和Read View,這就是我們在RC級別下的事務中可以看到別的事務提交的更新的原因

​  總結:在RC隔離級別下,是每個快照讀都會生成並獲取最新的Read View,而在RR隔離級別下,則是同一個事務中的第一個快照讀才會創建Read View,之后的快照讀獲取的都是同一個Read View


免責聲明!

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



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