亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Mysql InnoDB多版本并發(fā)控制MVCC詳解

 更新時(shí)間:2022年11月29日 08:33:15   作者:Cuzzz  
這篇文章主要介紹了Mysql InnoDB多版本并發(fā)控制MVCC詳解的相關(guān)資料,需要的朋友可以參考下

一丶為什么需要事務(wù)隔離級(jí)別

mysql是一個(gè)客戶端/服務(wù)端軟件,對(duì)于同一個(gè)服務(wù)器來(lái)說(shuō),可以有多個(gè)客戶端進(jìn)行連接,每一個(gè)客戶端進(jìn)行連接之后就形成一個(gè)會(huì)話,每一個(gè)客戶端都可以在自己的會(huì)話中向服務(wù)器發(fā)出請(qǐng)求語(yǔ)句,一個(gè)請(qǐng)求語(yǔ)句可能是某一個(gè)事務(wù)的一部分,服務(wù)器可以同時(shí)處理多個(gè)事務(wù)。

如果事務(wù)時(shí)一個(gè)接著一個(gè)進(jìn)行,那么下一個(gè)事務(wù)是在上一個(gè)事務(wù)的一致性前提下進(jìn)行的,就沒(méi)用一致性的問(wèn)題,但是事務(wù)是并發(fā)進(jìn)行且可能訪問(wèn)到相同的數(shù)據(jù)這時(shí)候就會(huì)出現(xiàn)如下問(wèn)題

可以看到AB最開(kāi)始總和13元,最后AB總和18元,銀行血虧五元,這顯然違背了一致性——錢(qián)的總量不變。這就是并發(fā)情況下兩個(gè)事務(wù)的影響,所以需要事務(wù)隔離讓事務(wù)隔離的進(jìn)行,互不干涉。

1.實(shí)現(xiàn)事務(wù)隔離的方式:串行執(zhí)行

最簡(jiǎn)單直接的方式,同一時(shí)間只能有一個(gè)事務(wù)運(yùn)行,這樣必然不會(huì)有上述不一致的情況,但是大大降低了吞吐率并增加了事務(wù)的等待時(shí)間

2.實(shí)現(xiàn)事務(wù)隔離的方式:可串行執(zhí)行

并發(fā)事務(wù)之所以出現(xiàn)不一致的情況,就是由于多個(gè)事務(wù)訪問(wèn)相同的數(shù)據(jù),需要實(shí)現(xiàn)多個(gè)事務(wù)在訪問(wèn)相同數(shù)據(jù)的時(shí)候進(jìn)行限制,比方說(shuō)上圖中事務(wù)2想訪問(wèn)A賬戶的值需要等待事務(wù)提交事務(wù)之后,這樣可以讓并發(fā)事務(wù)的執(zhí)行如同串行執(zhí)行的效果一樣。

二丶并發(fā)事務(wù)執(zhí)行的問(wèn)題:臟寫(xiě),臟讀,不可重復(fù)讀,幻讀

1.臟寫(xiě)

一個(gè)事務(wù)修改了另外一個(gè)未提交事務(wù)修改過(guò)的數(shù)據(jù)

臟寫(xiě)導(dǎo)致一致性無(wú)法保證

上圖事務(wù)A和事務(wù)B都更新紫色數(shù)據(jù),其中事務(wù)A首先更新為A,然后事務(wù)B過(guò)來(lái)更新為B,這時(shí)候事務(wù)A回滾后更新為Null,事務(wù) B 明明正常寫(xiě)了一行數(shù)據(jù),但是寫(xiě)完之后發(fā)現(xiàn)值變了,有點(diǎn)丟失更新的意思。(比如A表示余額,這時(shí)候在將余額A判斷是否足以支付,判斷得到可以,事務(wù)B執(zhí)行扣費(fèi)寫(xiě)入A-5,商家收到5元,結(jié)果這時(shí)候回滾了,A變成Null,事務(wù)A中轉(zhuǎn)錢(qián)的一方錢(qián)變?yōu)锳,錢(qián)的總額變?yōu)锳+5了)

臟寫(xiě)導(dǎo)致原子性受到破壞

假如上述的事務(wù)B還操作了另外的數(shù)據(jù),比如插入一條數(shù)據(jù)C,并且更改為B寫(xiě)入C是在一個(gè)事務(wù)下面的,需要具備原子性,但是臟寫(xiě)讓B的更改需要部分回滾為Null,這樣插入C和更改B就不具備原子性(比如A表示余額,這時(shí)候在將余額A判斷是否足以支付,判斷得到可以,事務(wù)B執(zhí)行扣費(fèi)寫(xiě)入A-5,商家收到5元,結(jié)果這時(shí)候回滾了,A變成Null,這時(shí)候部分回滾,商家的5元沒(méi)用回滾,商家的庫(kù)存也沒(méi)用回滾,原子性被破壞)

2.臟讀

如果一個(gè)事務(wù)讀取到另外一個(gè)事務(wù)未提交的數(shù)據(jù),意味著發(fā)生了臟讀

比如事務(wù)A先寫(xiě)數(shù)據(jù)A,然后事務(wù)B督導(dǎo)數(shù)據(jù)A后在內(nèi)存中使用A進(jìn)行一系列操作(比如A表示余額,這時(shí)候在將余額A判斷是否足以支付,判斷得到可以)但是事務(wù)A這時(shí)候回滾了,事務(wù)B再次讀取數(shù)據(jù)發(fā)現(xiàn)為null,這就是臟讀。

臟讀可能引發(fā)一致性的問(wèn)題:比如事務(wù)操作時(shí)修改x和y的值,并且二者總是相等的,A修改x為1,還沒(méi)來(lái)得及修改y也沒(méi)用提交事務(wù),這時(shí)候事務(wù)B讀取x=1,y=0,二者不等,事務(wù)B讀取到了數(shù)據(jù)庫(kù)不一致的狀態(tài),讀取到未提交事務(wù)的值

3.不可重復(fù)讀

假如一個(gè)事務(wù)修改了另外一個(gè)事務(wù)未提交的數(shù)據(jù),意味發(fā)生了不可重復(fù)讀

比如事務(wù)A第一次讀取到值為A,接著事務(wù)B修改為B,并且提交了事務(wù)B,然后事務(wù)A再次讀取得到的數(shù)據(jù)是B,同一行數(shù)據(jù)多次讀取值并不相同,這稱作不可重復(fù)讀。它是指在同一個(gè)事務(wù)里面查詢同一行數(shù)據(jù),每次查到的數(shù)據(jù)都不一樣。和臟讀區(qū)別在于臟讀是由于別的事務(wù)回滾導(dǎo)致,而不可重復(fù)讀讀到的其實(shí)是已經(jīng)提交的數(shù)據(jù)。

事務(wù)A讀到事務(wù)B提交后的數(shù)據(jù)似乎很合理,但是我們想象這樣一種場(chǎng)景:你有一個(gè)流水表和用戶余額,其中記錄用戶每天的流水,你在月初0點(diǎn)的時(shí)候核對(duì)流水和庫(kù)存,但是流水很多,你的程序選擇一個(gè)一個(gè)用戶的進(jìn)行核對(duì),核對(duì)用戶甲,甲沒(méi)做任何消費(fèi),但是當(dāng)你核對(duì)B的時(shí)候,你將B的流水load到內(nèi)存中,但是B這時(shí)候(0點(diǎn)30分,這一筆數(shù)據(jù)新的一個(gè)余額)進(jìn)行了扣除余額的操作,導(dǎo)致B余額和流水對(duì)不上了。

4.幻讀

如果一個(gè)事務(wù)A先根據(jù)沒(méi)用搜索條件查詢到一些記錄,在該事務(wù)未提交前,另外一個(gè)事務(wù)寫(xiě)入(delete,update,insert)了符合搜索條件的記錄,這時(shí)候事務(wù)A再次讀取,發(fā)現(xiàn)數(shù)據(jù)條數(shù)和第一次讀取的不同,如同出現(xiàn)了幻覺(jué),稱之為幻讀

事務(wù)A讀到事務(wù)B提交后的數(shù)據(jù)似乎很合理,但是我們想象這樣一種場(chǎng)景:你有一個(gè)需求將會(huì)公司的男性員工了女性員工查詢進(jìn)行展示,你先查詢了總數(shù)為100人,然后查詢男性的總數(shù)50人,后查詢女性人數(shù)準(zhǔn)備在頁(yè)面展示共100人,其中男50人,女50人,結(jié)果這是管理信息的人發(fā)現(xiàn)有一位員工性別錯(cuò)誤錄入了,將其從男修改為女,這時(shí)候你讀取事務(wù)就是女51人了,你在主頁(yè)顯示了共100人,其中男50人,女51人

三丶隔離級(jí)別

1.Read UnCommitted 讀未提交

在此隔離級(jí)別下,會(huì)發(fā)生臟讀,不可重復(fù)讀,和幻讀

2.Read Committed 讀已提交

在此隔離級(jí)別下,會(huì)發(fā)生不可重復(fù)讀,和幻讀

3.Repeatable Read 可重復(fù)讀

在此隔離級(jí)別下,可能發(fā)生幻讀

4.Serializable 可串行化

在此隔離級(jí)別下,不會(huì)發(fā)生臟讀,不可重復(fù)讀,和幻讀

其中臟寫(xiě)是對(duì)一致性影響最嚴(yán)重的,無(wú)論是何種隔離級(jí)別,都不允許臟寫(xiě)發(fā)生,innodb使用鎖保證不會(huì)出現(xiàn)臟寫(xiě)現(xiàn)象,第一個(gè)事務(wù)更新某條記錄的時(shí)候,會(huì)給這條記錄加鎖,另外一個(gè)事務(wù)在此更新的時(shí)候,需要等待第一個(gè)事務(wù)提交釋放鎖后更新。隔離級(jí)別越高,其并發(fā)能力越低。

四丶Mysql設(shè)置隔離級(jí)別

默認(rèn)隔離級(jí)別可重復(fù)讀

1.設(shè)置全局隔離級(jí)別

SET GLOBAL TRANSACTION ISOLATION LEVEL 期望的隔離級(jí)別(可選READ UNCOMMITED,READ COMMITED,REPEATABLE READ,SERIALIZABLE),此命令只對(duì)執(zhí)行語(yǔ)句后新產(chǎn)生的會(huì)話有效,對(duì)當(dāng)前已經(jīng)存在的會(huì)話無(wú)效

2.設(shè)置會(huì)話隔離級(jí)別

SET SESSION TRANSACTION ISOLATION LEVEL 期望的隔離級(jí)別(可選READ UNCOMMITED,READ COMMITED,REPEATABLE READ,SERIALIZABLE),對(duì)當(dāng)前會(huì)話后續(xù)事務(wù)有效,該語(yǔ)句可以在已開(kāi)啟的事務(wù)中執(zhí)行,但是不會(huì)影響當(dāng)前正在執(zhí)行的事務(wù),如果在事務(wù)之間執(zhí)行,只會(huì)對(duì)后續(xù)的事務(wù)有效

3.設(shè)置下一個(gè)事務(wù)的隔離級(jí)別

SET TRANSACTION ISOLATION LEVEL 期望的隔離級(jí)別(可選READ UNCOMMITED,READ COMMITED,REPEATABLE READ,SERIALIZABLE) 只對(duì)當(dāng)前會(huì)話的下一個(gè)即將開(kāi)啟的事務(wù)有效,下一個(gè)事務(wù)執(zhí)行完后,后續(xù)事務(wù)將恢復(fù)到之前的隔離級(jí)別,該語(yǔ)句不能再已經(jīng)開(kāi)啟的事務(wù)中執(zhí)行,否則會(huì)報(bào)錯(cuò)。

4.指定服務(wù)器的隔離級(jí)別

在啟動(dòng)的時(shí)候使用--transaction-isolation=xxx即可執(zhí)行默認(rèn)隔離級(jí)別

五丶MVCC原理

下面討論記錄對(duì)當(dāng)前事務(wù)是否可見(jiàn)都是基于當(dāng)前事務(wù)中執(zhí)行的查詢是快照讀(普通查詢),對(duì)于當(dāng)前讀(select xxx for update,select xxx lock in share mode)是不通用的

1.版本鏈

對(duì)于InnoDB存儲(chǔ)引擎來(lái)說(shuō),其聚簇索引記錄中包含兩個(gè)隱藏列:

trx_id:一個(gè)事務(wù)每次對(duì)聚簇索引記錄做出改動(dòng)的時(shí)候,都會(huì)把該事務(wù)的事務(wù)id復(fù)制給此列 roll_point:每次對(duì)某條聚簇索引記錄進(jìn)行改動(dòng)的時(shí),都會(huì)把舊的版本寫(xiě)入到undo 日志中,此列相當(dāng)于一個(gè)指針,指向修改前的信息

每次修改都會(huì)形成Undo 日志,所有版本的數(shù)據(jù)會(huì)通過(guò)roll_point串聯(lián)成一個(gè)鏈表,稱之為版本鏈,頭節(jié)點(diǎn)是當(dāng)前記錄的最新值。利用版本鏈控制多個(gè)并發(fā)事務(wù)訪問(wèn)相同記錄時(shí)的行為稱為MVCC多版本并發(fā)控制。

其實(shí)在undo日志中,只記錄被更新列的信息,而不是記錄全部的信息,對(duì)于沒(méi)有記錄的列,會(huì)通過(guò)版本鏈找少一個(gè)版本中的對(duì)應(yīng)列的信息,直到找到聚簇索引葉子節(jié)點(diǎn)中的內(nèi)容

2.Read View

對(duì)于使用Read Uncommitted隔離級(jí)別的事務(wù),可以讀取到?jīng)]提交的數(shù)據(jù),那么直接讀取最新的版本即可。對(duì)于Serializable隔離級(jí)別,innodb直接通過(guò)加鎖來(lái)訪問(wèn)記錄。對(duì)于read committed 和 repeatable read隔離級(jí)別的事務(wù),都必須保證督導(dǎo)的數(shù)據(jù)是已經(jīng)提交事務(wù)修改過(guò)的記錄,那么如何判斷版本鏈中的哪個(gè)版本的數(shù)據(jù)是當(dāng)前事務(wù)可見(jiàn)的昵?

innodb 使用的Read View

2.1 read view 的結(jié)構(gòu)

  • m_ids:在生成read view時(shí),當(dāng)前系統(tǒng)中活躍的讀寫(xiě)事務(wù)id列表
  • min_trx_id:生成read view時(shí),當(dāng)前系統(tǒng)中活躍的讀寫(xiě)事務(wù)中最小事務(wù)id,也就是m_ids中的最小值
  • max_trx_id:生成read view時(shí),系統(tǒng)應(yīng)該分配給下一個(gè)事務(wù)的事務(wù)id值
  • creator_trx_id:生成該read view的事務(wù)的事務(wù)id

2.2 read view

  • 如果被訪問(wèn)版本的trx_idcreator_trx_id相同,意味著當(dāng)前事務(wù)在訪問(wèn)自己修改的記錄,自然可見(jiàn)
  • 如果訪問(wèn)版本的trx_id屬性值小于read view中的min_trx_id 表明此版本是生成read view之前已經(jīng)提交的事務(wù),那么自然可見(jiàn)
  • 如果訪問(wèn)版本的trx_id,大于等于read view中的max_trx_id說(shuō)明,當(dāng)前版本數(shù)據(jù)是生成read view后開(kāi)啟事務(wù)產(chǎn)生的,那么自然不可見(jiàn)
  • 如果訪問(wèn)版本的trx_id 介于min_trx_idmax_trx_id之間,需要判斷trx_id是否位于m_ids列表中,如果在說(shuō)明創(chuàng)建read view時(shí)生成該版本的事務(wù)還是活躍的,那么該版本,不可被訪問(wèn),如果不在說(shuō)明創(chuàng)建read view 時(shí)生成該版本的事務(wù)已經(jīng)提交,可以被訪問(wèn)到

如果某個(gè)版本數(shù)據(jù)對(duì)當(dāng)前事務(wù)不可見(jiàn)那么需要一直順著版本鏈找上一個(gè)版本的數(shù)據(jù),并通過(guò)上述步驟判斷是否可見(jiàn),直到找到可見(jiàn)的版本,如果一直找不到說(shuō)明該條記錄對(duì)當(dāng)前事務(wù)不可見(jiàn),查詢結(jié)果將不包含該記錄。

2.3 Read Committed和 Repeatable Read的不同

Read Committed——每次讀取數(shù)據(jù)前都生成一個(gè)Read View

這樣可以保證生成Read view 中的m_ids是實(shí)時(shí)活躍事務(wù)id集合,也許第一次讀取的時(shí)候事務(wù)A沒(méi)提交,其id位于m_ids中,但是第二次讀取的時(shí)候事務(wù)A提交了,事務(wù)A將不位于m_ids中,這樣在第二次讀取的時(shí)候,通過(guò)m_ids判斷事務(wù)A是否提交的時(shí)候,可以得到事務(wù)A已經(jīng)提交了,然后讓事務(wù)A版本產(chǎn)生的數(shù)據(jù)可見(jiàn)(見(jiàn)2.2.4中的內(nèi)容)。

Repeatable Read——如果使用begin開(kāi)啟事務(wù)那么在第一次查詢的時(shí)候生成Read view,如果使用start transaction with consistent snapshot 那么執(zhí)行的時(shí)候就會(huì)生成read view

這樣可以保證當(dāng)前事務(wù)從頭到尾都是read view中記錄的內(nèi)容是一致的,第一次讀取的時(shí)候事務(wù)A沒(méi)有提交,那么不可見(jiàn),但是第二次讀取的時(shí)候事務(wù)A提交了,但是read view的m_idsmax_trx_id可以判斷事務(wù)A不可見(jiàn),比如事務(wù)A事務(wù)id小于max_trx_id意味著生成read view是事務(wù)A啟動(dòng)但是沒(méi)提交,即使第二次讀事務(wù)A提交了,但是m_ids中還是包含事務(wù)A,那么不可見(jiàn)。如果事務(wù)A事務(wù)id大于max_trx_id,那么自然第二次還是大于max_trx_id,也是不可見(jiàn)的,從而實(shí)現(xiàn)了可重復(fù)讀。

2.4 二級(jí)索引與MVCC

上面我們提到,innodb聚簇索引組織的記錄才具備trx_idroll_point,那么我們使用二級(jí)索引進(jìn)行查詢的時(shí)候,如何判斷數(shù)據(jù)是否可見(jiàn)昵?

  • 二級(jí)索引頁(yè)面的page header中存在page_max_trx_id屬性,每當(dāng)有事務(wù)對(duì)其中的記錄進(jìn)行增刪改查操作的時(shí)候,如果事務(wù)的事務(wù)id,大于page_max_trx_id,那么會(huì)更新page_max_trx_id屬性值為其事務(wù)id,這意味著page_max_trx_id記錄了修改該二級(jí)索引頁(yè)面最大的事務(wù)id是多少。當(dāng)select通過(guò)二級(jí)索引首先看下對(duì)于read view的min_trx_id是否大于該頁(yè)面的page_max_trx_id,如果大于那么頁(yè)面中所有記錄都對(duì)該read view可見(jiàn),否則就進(jìn)行下面的第二步
  • 利用二級(jí)索引中的主鍵值,進(jìn)行回標(biāo),得到對(duì)應(yīng)的聚簇索引記錄然后進(jìn)行回表,然后通過(guò)2.2中步驟拿到第一個(gè)可見(jiàn)版本的數(shù)據(jù),然后比對(duì)此紀(jì)錄和通過(guò)二級(jí)索引查詢得到記錄的值是否相同,如果相同那么發(fā)送給客戶端,否則跳過(guò)該記錄。

到此這篇關(guān)于Mysql InnoDB多版本并發(fā)控制MVCC詳解的文章就介紹到這了,更多相關(guān)Mysql InnoDB多版本并發(fā)控制MVCC內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論