MVCC是一種并發控制的方法,在數據庫管理系統中,實現對數據庫的并發訪問,在編程語言中實現事務內存
主要是為了提高數據庫并發性能,更好的處理讀寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞并發讀
- 當前讀
- select lock in share mode(共享鎖),select for update;update,insert,delete(排他鎖)
- 讀取的是記錄的最新版本,讀取時要保證其他事務不能修改當前記錄,會對讀取的記錄進行加鎖
- 快照讀
- 不加鎖的select操作就是快照讀,即不加鎖的非阻塞的
- 前提是隔離級別不是串行級別,串行級別下的快照讀回退化為當前讀
- 基于提高并發性能的考慮,快照讀的實現是基于多版本并發控制
- mvcc是行鎖的一個變種,在很多情況下,避免可加鎖操作,降低開銷
- 基于多版本,即快照讀可能讀到的并不一定是最新數據版本,可能是歷史版本
MVCC多版本并發控制指“維持一個數據的多個版本,使得讀寫操作沒有沖突”的概念
MySQL中快照讀就是實現MVCC理想模型其中一個非阻塞讀功能,相對而言,當前讀就是悲觀鎖的具體功能實現
快照讀本身也是抽象概念。MVCC模型在MySQL中實現由3個隱式字段:undo日志,read view等完成
優勢
mvcc是用來解決讀-寫沖突的無鎖并發控制,為事務分配單向長時間的時間戳,為每個修改保存一個版本,版本與事務時間戳關聯,讀操作只讀該事務開始前的數據庫快照
- 在并發讀寫數據庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數據庫并發讀寫的性能
- 同時還可以解決臟讀,幻讀,不可重復讀等事務隔離問題,但不能解決更新丟失問題
MVCC+悲觀鎖:MVCC解決讀寫沖突,悲觀鎖解決寫寫沖突
MVCC+樂觀鎖:MVCC解決讀寫重讀,樂觀鎖解決讀寫沖突
實現原理
Rollback Segments 用來臨時保存當數據庫發生改變時的先前值
- 因某種原因或其他用戶想要通過ROLLBACK聲明取消一個數據操作,數據就會復原到之前改變時的值
- 只在transaction過程中有效,用戶執行COMMIT命令,Rollback Segment里面的值就會標識為失效的,數據改變為永久化
- 當有并發session訪問一個數據值改變但事務還沒有提交的表
- select語句開始讀取一個表同時一個事務也在修改這個表值,修改前的值就保存到Rollback Segment中
- select語句也是從Rollback Segment里讀取表的值
隱式字段
DB_TRX_ID
:6byte,最近修改(update/insert/delete)事務ID;記錄創建/最后一次修改該記錄的事務IDDB_ROLL_PTR
:7byte,回滾指針,指向這條記錄的上一個版本(存儲在rollback segment中)DB_ROW_ID
:6byte,隱含的自增ID(隱藏主鍵),如果數據表沒有主鍵,InnoDB會自動以DB_ROW_ID
產生一個聚簇索引實際還有一個刪除flag隱藏字段,既記錄被更新或刪除并不代表真的刪除,而是刪除的flag改變(軟刪除字段)
undo日志
insert undo log
:- 代表事務在insert新紀錄時產生的undo log
- 只在事務回滾時需要
- 在事務提交后立即丟棄
update undo log
:- 事務在進行update或delete時產生的undo log
- 在事務回滾和快照讀時需要
- 不能隨便刪除,只有在快照讀或事務回滾不涉及該日志時,對應的日志才會被
purge
線程統一刪除
purge
- 實現InnoDB的MVCC機制,更新或刪除操作都只是設置老記錄的deleted_bit,不是真正將過時的記錄刪除
- deleted_bit是一個標志位
- 當執行刪除操作時,并不是將記錄從數據頁中物理刪除,而是將deleted_bit設為1,表示記錄被刪除
- 更新操作,會創建一個新的記錄版本,并將舊記錄的deleted_bit設為1,時舊記錄類似刪除,新紀錄包含更新后數據
- 節省磁盤空間,有purge線程來清理deleted_bit為true的記錄,同時該線程自己維護一個read view
- 當記錄為true并
DB_TRX_ID
相對purge線程的read view可見,那么記錄被安全清除 - InnoDB中垃圾回收機制,當確認沒有事務需要訪問deleted_bit為1記錄時,才被物理刪除
- 當記錄為true并