MySql,MVCC實現(xiàn)及其機制,快照讀在RC,RR下的區(qū)別說明
一、什么是MVCC
多版本并發(fā)控制
Multiversion Concurrency Control
大部分的MySQL的存儲 引擎,比如InnoDB,F(xiàn)alcon,以及PBXT并不是簡簡單單的使用行鎖機制。它們都使用了行鎖結合一種提高并發(fā)的技術,被稱為MVCC(多版本并 發(fā)控制)。MVCC并不單單應用在MySQL中,其他的數(shù)據庫如Oracle,PostgreSQL,以及其他數(shù)據庫也使用這個技術?!?/p>
MVCC避免了許多需要加鎖的情形以及降低消耗。這取決于它實現(xiàn)的方式,它允許非阻塞讀取,在寫的操作的時候阻塞必要的記錄。
MVCC保存了某一時刻數(shù)據的一個快照。意思就是無論事物運行了多久,它們都能看到一致的數(shù)據。也就是說在相同的時間下,不同的事物看相同表的數(shù)據是不同的。如果你從來沒有這方面的經驗,可能說這些有點令人困惑。但是在以后這個會很容易理解和熟悉的。
每個存儲引擎實現(xiàn)MVCC方式都是不同的。有許多種包含了樂觀(optimistic)和悲觀(pessimistic)的并發(fā)控制。我們用簡單的InnoDb的行為來舉例說明MVCC工作方式。
InnoDB實現(xiàn)MVCC的方法是,它存儲了每一行的兩個額外的隱藏字段,這兩個隱藏字段分別記錄了行的創(chuàng)建的時間和刪除的時間。在每個事件發(fā)生的時 候,每行存儲版本號,而不是存儲事件實際發(fā)生的時間。每次事物的開始這個版本號都會增加。自記錄時間開始,每個事物都會保存記錄的系統(tǒng)版本號。依照事物的 版本來檢查每行的版本號。在事物隔離級別為可重復讀的情況下,來看看怎樣應用它。
SELECT
- InnoDB檢查每行,要確定它符合兩個標準。
- InnoDB必須知道行的版本號,這個行的版本號至少要和事物版本號一樣的老。(也就是是說它的版本號可能少于或者和事物版本號相同)。這個既能確定事物開始之前行是存在的,也能確定事物創(chuàng)建或修改了這行。
- 行的刪除操作的版本一定是未定義的或者大于事物的版本號。確定了事物開始之前,行沒有被刪除。
- 符合了以上兩點。會返回查詢結果。
INSERT
- InnoDB記錄了當前新增行的系統(tǒng)版本號。
DELETE
- InnoDB記錄的刪除行的系統(tǒng)版本號作為行的刪除ID。
UPDATE
- InnoDB復制了一行。這個新行的版本號使用了系統(tǒng)版本號。它也把系統(tǒng)版本號作為了刪除行的版本。
所有其他記錄的結果保存是,從未獲得鎖的查詢。這樣它們查詢的數(shù)據就會盡可能的快。要確定查詢行要遵循這些標準。缺點是存儲引擎要為每一行存儲更多的數(shù)據,檢查行的時候要做更多的處理以及其他內部的一些操作。
MVCC只能在可重復讀和可提交讀的隔離級別下生效。不可提交讀不能使用它的原因是不能讀取符合事物版本的行版本。它們總是讀取最新的行版本??尚蛄谢荒苁褂肕VCC的原因是,它總是要鎖定行。
下面的表說明了在MySQL中不同鎖的模式以及并發(fā)級別。
我們在操作數(shù)據庫的時候總是這四大類 讀讀 讀寫 寫讀 寫寫,讀讀肯定是沒有任務數(shù)據問題的,但對事物有了解的同學就會知道,讀寫、寫寫操作很容易就會導致數(shù)據不一致。
在此之前解決這類問題的常用方式就是 加鎖,聽名字就知道這是個很復雜、很耗性能的操作,所以大神們不滿足這個操作,從而在MySQL里面實現(xiàn)了MVCC。
MVCC并不是MySQL獨有的,它是一個理念,百度百科解釋如下:
Multi-Version Concurrency Control 多版本并發(fā)控制,MVCC 是一種并發(fā)控制的方法,一般在數(shù)據庫管理系統(tǒng)中,實現(xiàn)對數(shù)據庫的并發(fā)訪問;在編程語言中實現(xiàn)事務內存。
MVCC里面有一些關鍵詞,理解這些關鍵詞,你就明白了什么是MVCC。MVCC是解決讀寫、寫讀導致數(shù)據不一致的問題,寫寫問題還是需要加鎖來解決。
所以我們可以使用 MVCC + 鎖(樂觀鎖/悲觀鎖)來解決全部的問題。
二、當前讀、快照讀
當前讀就是讀取最新的數(shù)據,為了保證讀取的是最新且準確的數(shù)據,所以它在讀取的時候會加鎖,防止其它事物操作。
快照讀是不加鎖的方式,當一個事物要操作數(shù)據庫的時候,會在這個事物的基礎上形成一個快照,其它的操作就讀取這個快照。
MVCC就是基于快照讀來實現(xiàn)的,在MySQL里面的快照讀是基于這樣幾個關鍵點來實現(xiàn)的
- 三個隱藏參數(shù) (DB_ROW_ID 隱藏主鍵id、DB_ROLL_PTR 回滾指針、DB_TRX_ID 事物id)
- undo log 日志
- read view
三、隱藏字段
假如我們有一張表,里面有兩個字段,name、age,但實際上我們表里的數(shù)據是這樣的
3-1、隱藏主鍵
6byte,隱含的自增ID(隱藏主鍵),如果數(shù)據表沒有主鍵,InnoDB會自動以DB_ROW_ID產生一個聚簇索引
聚簇索引:數(shù)據存儲和索引是存在一起的,邏輯上和物理上都是一起的,一個表只能有一個聚簇索引。
注:理解聚簇索引可以很好的理解MySQL的索引規(guī)則,感興趣的可以看看這個 MySQL索引詳解
3-2、事物id
記錄這條記錄最后一次操作的事物id
3-3、回滾指針
回滾指針,指向這條記錄的上一個版本(存儲于rollback segment里),用于配合下面的 undo log。
四、undo log
undo log 日志分為兩種
(1)、 insert undo log 數(shù)據庫在插入數(shù)據的時候產生,只有在當前事物回滾的時候才有用,所以在當前事物結束的時候它就沒用了,就會被刪除。
(2)、 update undo log 數(shù)據庫在更新、刪除的時候產生,除了當前事物會使用,在快照讀的時候也會使用,所以不能隨便刪除,只有在快速讀或事務回滾不涉及該日志時,對應的日志才會被purge線程統(tǒng)一清除。
五、Read View
什么是讀視圖呢?數(shù)據庫的操作都是多個事物同時進行的,有讀有寫。假如當前有兩個事物,A事物讀取,B事物正在更新數(shù)據。
在A事物開始的時候,就形成當前數(shù)據庫的一個快照,記錄并維護系統(tǒng)當前活躍事務的ID。read view 主要是用來做可見性判斷的,它會判斷每條記錄的的數(shù)據,這條數(shù)據可能是真實的數(shù)據,也可能是undo log 中的數(shù)據。
read view 用一個可見性的算法,來判斷當前是讀取真實的數(shù)據,還是undo log的數(shù)據。這里可以簡單理解read view 內部維護了一個事物id列表,里面有最大值和最小值,可以判斷其它事物的id是否在這個可見范圍內。
N、其它
N-1、快照讀在RC和RR下的區(qū)別
- RC (read-committed)讀已提交, 可能會導致 不可重復讀、幻讀
- RR (repeatable-read)可重復讀,可能會導致 不可重復讀
幻讀 : 事物A查詢數(shù)據庫查詢出來了20條數(shù)據,然后事物B刪除了2條數(shù)據,這時候事物A再去查詢發(fā)現(xiàn)只有18條了,從而產生了幻覺。
我們知道在RR級別下面不會產生幻讀,之所以不會產生幻讀,是快照讀在RC和RR下的生成的策略不一樣。
RC隔離級別下,是每個快照讀都會生成并獲取最新的Read View;而在RR隔離級別下,則是同一個事務中的第一個快照讀才會創(chuàng)建Read View, 之后的快照讀獲取的都是同一個Read View。
MySQL/InnoDB定義的4種隔離級別:
Read Uncommited
- 可以讀取未提交記錄。
Read Committed (RC)
- 針對當前讀,RC隔離級別保證對讀取到的記錄加鎖 (記錄鎖),存在幻讀現(xiàn)象
Repeatable Read (RR)(默認)
- 針對當前讀,RR隔離級別保證對讀取到的記錄加鎖 (記錄鎖),同時保證對讀取的范圍加鎖,新的滿足查詢條件的記錄不能夠插入 (間隙鎖),不存在幻讀現(xiàn)象。
Serializable
- 從MVCC并發(fā)控制退化為基于鎖的并發(fā)控制。不區(qū)別快照讀與當前讀,所有的讀操作均為當前讀,讀加讀鎖 (S鎖),寫加寫鎖 (X鎖)。
- Serializable隔離級別下,讀寫沖突,因此并發(fā)度急劇下降,在MySQL/InnoDB下不建議使用。
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
mysql多表join時候update更新數(shù)據的方法
如果item表的name字段為''就用resource_library 表的resource_name字段前面加上字符串Review更新它,他們的關聯(lián)關系在表resource_review_link中。2011-03-03詳解MySQL?substring()?字符串截取函數(shù)
MySQL 查詢數(shù)據有時候需要對數(shù)據項進行日期格式化或截取特定部分的操作,當需要對字符串進行截取加工時用到了 substring() 函數(shù),這篇文章主要介紹了MySQL?substring()?字符串截取函數(shù),需要的朋友可以參考下2022-07-07