一陋葡、什么是MVCC
MVCC,全稱 Multi-Version Concurrency Control 彻采,MVCC是多版本并發(fā)控制的全稱腐缤,是指多版本的并發(fā)控制。MVCC是一種并發(fā)控制方法肛响。通常岭粤,在數(shù)據(jù)庫管理系統(tǒng)中,它用編程語言實(shí)現(xiàn)對(duì)數(shù)據(jù)庫和事務(wù)存儲(chǔ)器的并發(fā)訪問特笋。
MVCC 是一種在讀取數(shù)據(jù)時(shí)無需鎖定(加鎖)即可提高讀取效率和并發(fā)性的方法剃浇。
數(shù)據(jù)庫并發(fā)有以下情況:
1、讀-讀:沒有問題猎物。
2虎囚、讀-寫:存在線程安全問題,這可能導(dǎo)致臟讀蔫磨、幻讀和不可重復(fù)讀淘讥。
3、寫-寫:存在線程安全問題堤如,更新可能會(huì)丟失适揉。
二、MVCC的實(shí)現(xiàn)原理
這里面講解了煤惩,事務(wù)的特性、事務(wù)的隔離級(jí)別炼邀,當(dāng)時(shí)說MySQL事務(wù)實(shí)現(xiàn)原理有單版本控制——鎖魄揉,以及多版本控制MVCC。
現(xiàn)在我們需要知道拭宁,在讀已提交(RC洛退,Read Committed)和可重復(fù)讀(RR,Repeatable Read)隔離級(jí)別下的快照讀杰标,都是基于MVCC實(shí)現(xiàn)的兵怯!
MVCC最大的優(yōu)點(diǎn)是沒有讀鎖,讀寫之間沒有沖突腔剂。在讀多寫少的OLTP(On-Line Transaction Processing媒区,聯(lián)機(jī)事務(wù)處理)應(yīng)用程序中,讀寫之間沒有沖突非常重要,這大大提高了系統(tǒng)的并發(fā)性袜漩。
1绪爸、MVCC多版本實(shí)現(xiàn)
為了讓您更直觀地理解MVCC的實(shí)現(xiàn)原理,這里通過事務(wù)更新一行記錄的過程的例子宙攻,來解釋MVCC中多個(gè)版本的實(shí)現(xiàn)奠货。
假設(shè) ID~……是表中字段的名稱(DATA)。最后三個(gè)隱藏字段對(duì)應(yīng)對(duì)應(yīng)行的隱藏ID座掘、事務(wù)編號(hào)和回滾指針递惋,如下圖所示:
隱含ID(DB_ROW_ID),6字節(jié)溢陪,當(dāng)InnoDB自動(dòng)生成聚集索引時(shí)萍虽,聚集索引包括這個(gè)DB_ROW_ ID的值。
事務(wù)編號(hào)(DB_TRX_ID)嬉愧,6字節(jié)贩挣,它標(biāo)記了此行最新更新記錄的事務(wù)ID。每個(gè)事務(wù)都被處理没酣,其值自動(dòng)為+1王财。
回滾指針(DB_ROLL_PT),7個(gè)字節(jié)裕便,指向當(dāng)前記錄項(xiàng)的回滾段的撤消日志記錄绒净,通過該記錄可以找到以前版本的數(shù)據(jù)。
具體更新過程簡述如下:
首先偿衰,如果數(shù)據(jù)只是INSERT挂疆,則可以認(rèn)為ID是 1,其他兩個(gè)字段為空下翎。
當(dāng) 事務(wù)1 更改此行的數(shù)據(jù)值時(shí)缤言,將執(zhí)行,一视事、使用獨(dú)占鎖鎖定行胆萧,記錄重做日志;二俐东、將修改前這一行的值復(fù)制到Undo日志跌穗;三、修改當(dāng)前行的值虏辫,填寫事務(wù)ID蚌吸,并使回滾指針指向撤銷日志中修改前的行。
接下來砌庄,與 事務(wù)1 相同羹唠。此時(shí)奕枢,undo 日志中有兩行記錄,它們由回滾指針連接肉迫。
因此验辞,如果撤消日志沒有一直被刪除,那么當(dāng)前記錄的回滾指針將追溯到創(chuàng)建該行時(shí)的初始內(nèi)容喊衫。InnoDB中有一個(gè)清除線程跌造,將查詢比最舊的活動(dòng)事務(wù)更早的撤消日志并將其刪除,從而確保撤消日志文件不會(huì)無限增長族购。
2壳贪、MVCC 實(shí)現(xiàn)原理
它的實(shí)現(xiàn)原理主要是依賴記錄中的 3個(gè)隱式字段(DB_ROW_ID、DB_TRX_ID寝杖、DB_ROLL_PT)违施,undo日志 , Read View 來實(shí)現(xiàn)的瑟幕。
上面我們已經(jīng)詳細(xì)介紹了3個(gè)隱式字段的含義磕蒲,總結(jié)一下
默認(rèn)情況下,DB_ROW_ID 是數(shù)據(jù)庫為這行記錄生成的唯一隱式主鍵只盹。DB_TRX_ID 是當(dāng)前操作記錄的事務(wù)ID辣往,而 DB_ROLL_PTR 是一個(gè)回滾指針,與撤消日志一起使用以指向以前的舊版本殖卑。
有兩種 undo 日志:insert undo log站削、update undo log,幫助MVCC的撤銷的本質(zhì)是update undo log 孵稽。事實(shí)上许起,撤消日志是回滾段中的舊記錄鏈。(MySQL日志系統(tǒng)的詳解:(待補(bǔ)充))菩鲜。
3园细、什么是 Read View
什么是 Read View ?
Read View 是事務(wù)執(zhí)行快照讀取操作時(shí)生成的視圖接校。在事務(wù)執(zhí)行快照讀取時(shí)珊肃,將生成數(shù)據(jù)庫系統(tǒng)的當(dāng)前快照,并記錄和維護(hù)系統(tǒng)當(dāng)前活動(dòng)事務(wù)的ID(當(dāng)每個(gè)事務(wù)啟動(dòng)時(shí)馅笙,將分配一個(gè)ID,該ID是增量的厉亏,因此最新事務(wù)的ID值更大)董习。
當(dāng)我們使用select讀取數(shù)據(jù)時(shí),此時(shí)會(huì)有許多版本的數(shù)據(jù)爱只,但我們不知道要讀取哪個(gè)版本皿淋。
此時(shí),我們依賴readview來限制我們可以讀取的版本。只有通過readview才能知道我們可以閱讀哪個(gè)版本窝趣。
3.1疯暑、Read View 解析
Read View主要用于進(jìn)行可見性判斷,也就是說哑舒,當(dāng)我們?yōu)槭聞?wù)執(zhí)行快照讀時(shí)妇拯,我們會(huì)為記錄創(chuàng)建一個(gè)讀取視圖 Read View。以判斷當(dāng)前事務(wù)可以看到哪個(gè)版本的數(shù)據(jù)洗鸵。它可能是當(dāng)前期間的最新數(shù)據(jù)越锈,也可能是記錄 undo log 中某個(gè)版本的數(shù)據(jù)。
讀取視圖遵循可見性算法膘滨,主要是要修改的數(shù)據(jù)的最新記錄中的 DB_TRX_ID (即當(dāng)前事務(wù)ID)甘凭,并與系統(tǒng)中其他活動(dòng)事務(wù)的ID(由讀取視圖 Read View 維護(hù))進(jìn)行比較。
如果 DB_TRX_ID 跟 Read View 屬性不符合可見性火邓,通過 DB_ROLL_PTR 回滾指針在撤消日志Undo Log中的 DB_TRX_ID 比較中檢索數(shù)據(jù)庫(遍歷鏈表的 DB_TRX_ID)丹弱。
遍歷鏈接列表的DB _ TRX_ ID(從鏈的開始到鏈的結(jié)束,即從最近的修改)铲咨,直到找到滿足特定條件的 DB_TRX_ID , 那么這個(gè) DB_TRX_ID 所在的舊記錄就是當(dāng)前事務(wù)能看見的最新老版本躲胳。
3.2、Read View 含義
在一個(gè) Read View 快照中主要包括以下這些字段:
m_ids鸣驱,表示生成 Read View 時(shí)當(dāng)前系統(tǒng)中活動(dòng)讀/寫事務(wù)的事務(wù)ID列表
min_trx_id泛鸟,表示生成 Read View 時(shí)當(dāng)前系統(tǒng)中活動(dòng)讀/寫事務(wù)中最小的事務(wù)ID,即 m_ids 最小值
max_trx_id踊东,表示生成 Read View 時(shí)應(yīng)分配給系統(tǒng)中下一個(gè)事務(wù)的ID值
creator_trx_id,表示生成 Read View 的事務(wù)的事務(wù)ID
3.3北滥、Read View 如何判斷版本鏈可用
trx_id == creator_trx_id,可以訪問這個(gè)版本闸翅;
trx_id < min_trx_id再芋,可以訪問這個(gè)版本;trx_id > max_trx_id坚冀,不可以訪問這個(gè)版本;
min_trx_id <= trx_id <= max_trx_id济赎,如果 trx_id 在 m_ids 中不可以訪問,反之可以
三记某、當(dāng)前讀司训,快照讀與MVCC
1、什么是當(dāng)前讀和快照讀
1.1液南、當(dāng)前讀
select lock in share mode (共享鎖), select for update; update; insert; delete (排他鎖)這些操作都是一種當(dāng)前讀壳猜。
它讀取最新版本的記錄,讀取時(shí)滑凉,它還確保其他并發(fā)事務(wù)無法修改當(dāng)前記錄统扳,并鎖定讀取的記錄喘帚。
1.2、快照讀
不加鎖的 select 操作就是快照讀咒钟,即無鎖的非阻塞讀却涤伞;
快照讀的前提是隔離級(jí)別不是串行級(jí)別朱嘴,在串行級(jí)別下讀取的快照將退化為當(dāng)前讀取倾鲫,發(fā)生快照讀的原因是基于提高并發(fā)性能的考慮。
快照讀的實(shí)現(xiàn)基于多版本并發(fā)控制腕够,即MVCC级乍。MVCC可以被認(rèn)為是行鎖的變體,但在許多情況下帚湘,它避免了鎖操作并減少了開銷玫荣;由于它基于多個(gè)版本,也就是說大诸,讀取的快照可能不是數(shù)據(jù)的最新版本捅厂,而是以前的歷史版本
MVCC的設(shè)計(jì)目的是在不鎖定讀寫沖突,這種讀取指的是快照讀取资柔,而不是當(dāng)前讀取焙贷。
當(dāng)前的讀取實(shí)際上是一個(gè)鎖操作,這是悲觀鎖的實(shí)現(xiàn)
2贿堰、快照讀辙芍、當(dāng)前讀與MVCC辨析
MVCC多版本并發(fā)控制的概念是“維護(hù)一個(gè)數(shù)據(jù)的多個(gè)版本,以便讀寫操作之間沒有沖突”羹与。
因?yàn)镸VCC只是一個(gè)抽象的概念故硅,為了實(shí)現(xiàn)這樣的概念,MySQL需要提供特定的功能來實(shí)現(xiàn)它纵搁〕孕疲“快照讀取是MySQL MVCC理想模型的非阻塞讀取功能之一”。
相對(duì)而言腾誉,當(dāng)前讀是悲觀鎖的具體功能實(shí)現(xiàn)徘层,快照閱讀本身也是一個(gè)抽象概念。
3利职、MVCC 只在 RC 和 RR 隔離級(jí)別下工作
一趣效、 在RC(Read Commited )的隔離級(jí)別下,每次快照讀取都會(huì)生成并獲得最新的 readview猪贪。
二英支、在RR(Repeatable Read)隔離級(jí)別,只有讀取同一事務(wù)的第一個(gè)快照才能創(chuàng)建 readview哮伟。每個(gè)后續(xù)快照讀取都使用相同的 readview干花,因此每個(gè)查詢結(jié)果都相同。