MySQL 鎖 ——No.4 當前讀夜涕、快照讀犯犁、快照讀實現(xiàn)原理及RC|RR 隔離級別下的 InnoDB 的非阻塞讀如何實現(xiàn)

當前讀

諸如select ... lock in share modeselect ... for update女器、update酸役、deleteinsert均為當前讀驾胆;當前讀本質(zhì)上是加了鎖的增刪該查語句涣澡,無論上的是共享鎖還是排他鎖均為當前讀.
這些語句被稱為當前讀的根本原因是因為它讀取的是記錄的最新版本,并且在讀取之后丧诺,還需保證其他事務(wù)不能修改當前記錄入桂,對讀取的記錄加鎖;上面的除 select 語句加的是共享鎖外驳阎,其他的都是排他鎖抗愁,那為什么 update馁蒂、deleteinsert也被稱為當前讀呢蜘腌?
我們都知道 RSBMS 主要由兩大部分組成沫屡,一部分是程序?qū)嵗?MySQL 實例),另一部分是存儲(即 InnoDB)撮珠,
我們在執(zhí)行 update語句更新某幾行數(shù)據(jù)時沮脖,每次都需要先讀取相應(yīng)數(shù)據(jù)行,然后在更新芯急,這個時候在讀取的時候需要讀取最新行勺届,所以需要使用當前讀

快照讀

快照讀也叫非阻塞讀,即所謂快照讀就是不加鎖的非阻塞讀志于,就是我們最簡單的 select操作

當然了涮因,這里不加鎖的非阻塞讀是以事務(wù)隔離級別不為最高級別的前提下成立废睦,因為在最高隔離級別下伺绽,快照讀也會變成當前讀,在其后自動加lock in share mode

快照讀的實現(xiàn)原理

之所以出現(xiàn)快照讀嗜湃,是基于提升并發(fā)訪問性能考慮的奈应;快照讀的實現(xiàn)是基于多版本的并發(fā)控制,即 MVCC购披,可以認為 MVCC 是行級鎖的一個變種杖挣,但是它在很多情況下避免了加鎖的操作,因此開銷更低.
既然基于多版本實現(xiàn)刚陡,那么快照讀有可能讀到的并不是數(shù)據(jù)的最新版本惩妇,可能是之前的歷史版本。

在 RC【Read Committed】 隔離級別下筐乳,快照讀和當前讀讀到讀數(shù)據(jù)版本是一樣的歌殃;

演示.

1.開啟兩個會話,并設(shè)置相應(yīng)的事務(wù)隔離級別為 RC

【下面的命令是基于 MySQL 8.0的蝙云,8以下的版本可以自行查找相應(yīng)的命令進行替換】
通過show variables like 'transaction%';查看會話的隔離級別氓皱,然后通過set session transaction isolation level read committed;設(shè)置會話的隔離級別為 RC

image.png

2.在一個會話中查詢數(shù)據(jù),另一個會話中修改相應(yīng)數(shù)據(jù)

1)會話 1 中查詢 deptno = 10 的 loc 為 NEW YORK

image.png

2)會話 2 中修改 deptno = 10 的 loc 為紐約
image.png

3)在會話1中分別使用當前讀和快照讀讀取 deptno = 10 的數(shù)據(jù)
發(fā)現(xiàn)使用快照讀和當前讀讀取到到數(shù)據(jù)是一樣的勃刨,即在 RR 隔離級別下波材,使用快照讀讀取到到也是最新數(shù)據(jù)
image.png

而在 RR【Repeatable Read】隔離級別下,當前讀返回的是數(shù)據(jù)的最新版本身隐,而快照讀在該隔離級別下可能讀到數(shù)據(jù)的歷史版本.在 RR 隔離級別下廷区,事務(wù)首次調(diào)用快照讀的時機很關(guān)鍵,即創(chuàng)造快照的時機決定了快照的版本

演示

1. 第一種情況贾铝,會話 1 先快照讀讀取 deptno = 40 的數(shù)據(jù)行躲因,會話2修改 deptno = 40的數(shù)據(jù)行的 loc = 奧地利早敬,并提交會話,然后比較會話 1 通過快照讀和當前讀讀取讀數(shù)據(jù)情況
1)會話 1 先快照讀讀取 deptno = 40 的數(shù)據(jù)行

image.png

2)會話2修改 deptno = 40的數(shù)據(jù)行的 loc = 奧地利大脉,并提交搞监,并查詢結(jié)果顯示已修改成功
image.png

3)比較會話 1 通過快照讀和當前讀讀取讀數(shù)據(jù)情況
結(jié)果顯示,快照讀讀取到的是舊數(shù)據(jù)镰矿,而當前讀讀到讀是最新數(shù)據(jù)
image.png

1. 第二種情況琐驴,會話2修改 deptno = 40的數(shù)據(jù)行的 loc = 烏克蘭,并提交會話秤标,然后比較會話 1 通過快照讀和當前讀讀取讀數(shù)據(jù)情況
1)會話2修改 deptno = 40的數(shù)據(jù)行的 loc = 烏克蘭绝淡,并提交會話

image.png

2)比較會話 1 通過快照讀和當前讀讀取讀數(shù)據(jù)情況
可以看到當前讀和快照讀讀取到的數(shù)據(jù)是一致的
image.png

RC|RR 隔離級別下的 InnoDB 的非阻塞讀【即快照讀】如何實現(xiàn)

快照讀的實現(xiàn)依賴三個因素;每行數(shù)據(jù)記錄除了存儲數(shù)據(jù)以外苍姜,還有一些額外的字段牢酵,其中最關(guān)鍵的是三個:DB_TRX_ID、DB_ROLL_PTR衙猪、DB_ROW_ID字段

DB_TRX_ID

該字段用來標識最近一次對本行記錄做修改馍乙,無論是insert,還是update垫释,它都是事務(wù)的標識符丝格,即最后一次修改本行記錄的事務(wù)ID,delete對于innodb來說也是一個update操作棵譬,更新行中的一個特殊位显蝌,將行標識為deleted,并非做真正的刪除【每次開啟一個事務(wù)的時候订咸,該事務(wù)ID就會遞增曼尊,即越新開啟的事務(wù),它的 事務(wù) ID 越大】

DB_ROLL_PTR

回滾指針脏嚷,只寫入回滾段( roll back segment)的undo 日志記錄骆撇。如果一行記錄被更新,則undo log report 包含重建該行記錄被更新之前內(nèi)容所必須的信息然眼。

DB_ROW_ID

即行號包含一個隨著新行插入而單調(diào)遞增的行ID艾船,當innodb自動產(chǎn)生聚集索引時,聚集索引會包括這個行ID的值高每,否則這個行ID不會出現(xiàn)在任何索引中屿岂。 (以前提到的,在innodb存儲引擎中鲸匿,如果表中沒有設(shè)置主鍵并且無唯一鍵時爷怀,Innodb會為我們創(chuàng)建一個隱藏主鍵字段,即我們這里的DB_ROW_ID)
光有上面這三個字段带欢,并不足以實現(xiàn)快照讀运授,還需要依托undo日志烤惊。

undo 日志

當我們對記錄做了變更操作時,就會產(chǎn)生undo記錄吁朦,undo記錄中存儲的是老版數(shù)據(jù)柒室,當一個舊的事務(wù)需要讀取數(shù)據(jù)時,為了能夠讀取到老版本的數(shù)據(jù)逗宜,需要順著undo列找到滿足其可見性的記錄雄右,這個找滿足可見行的記錄依賴 read view
undo 日志主要分為兩種:即insert undo log 和 update undo log.

insert undo log

表示的是事務(wù)對insert新記錄產(chǎn)生的undo log,只在事務(wù)回滾時需要纺讲,并且在事務(wù)提交后就可以立即丟棄

update undo log

事務(wù)對記錄進行delete或者update操作時產(chǎn)生的undo log擂仍,不僅在事務(wù)回滾時需要,快照讀也需要熬甚,所以不能隨便刪除逢渔,只有當數(shù)據(jù)庫所使用的快照中不涉及該日志記錄,對應(yīng)的回滾日志才會被線程刪除乡括。

read view

read view主要是用來做可見性判斷的肃廓,即當我們?nèi)?zhí)行快照讀 select 的時候,會針對我們查詢的數(shù)據(jù)創(chuàng)建出一個 read view粟判,來決定當前事務(wù)能看到的是哪個版本的數(shù)據(jù)亿昏,有可能是當前最新版本的數(shù)據(jù)峦剔,也可能是 undo log 中某個版本的數(shù)據(jù)档礁,read view 遵循一個可見性算法。主要是將要修改的數(shù)據(jù)的 DB_TRX_ID 取出來吝沫,與系統(tǒng)其他活躍事務(wù)ID【DB_TRX_ID】做對比呻澜,如果大于或者等于這些 ID 的話,就通過 DB_ROW_PTR 指針去取出 un do log惨险,上一層的 DB_TRX_ID 直到小于這些活躍事務(wù) ID 為止羹幸,這樣就保證了我們獲取到的數(shù)據(jù)版本是當前可見的最穩(wěn)定的版本

總結(jié)

正是以上的三個因子才使得 InnoDB 在 RR、RC 隔離級別下支持非阻塞讀辫愉,而讀取數(shù)據(jù)時的非阻塞就是所謂的 MVCC【Multiversion concurrency control】 栅受,而 InnDB 非阻塞讀機制實現(xiàn)了仿照版的 MVCC,MVCC 代表多版本并發(fā)控制恭朗,讀不加鎖屏镊,讀寫不沖突,極大的增加了系統(tǒng)的并發(fā)性能痰腮,那為什么是偽 MVCC 機制呢而芥,因為并沒有實現(xiàn)核心的多版本并存,而undo log 中的內(nèi)容只是串行化的結(jié)果膀值,記錄了多個事務(wù)的過程棍丐,不屬于多版本共存误辑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市歌逢,隨后出現(xiàn)的幾起案子巾钉,更是在濱河造成了極大的恐慌,老刑警劉巖秘案,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睛琳,死亡現(xiàn)場離奇詭異,居然都是意外死亡踏烙,警方通過查閱死者的電腦和手機师骗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讨惩,“玉大人辟癌,你說我怎么就攤上這事〖瞿恚” “怎么了黍少?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長处面。 經(jīng)常有香客問我厂置,道長,這世上最難降的妖魔是什么魂角? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任昵济,我火速辦了婚禮,結(jié)果婚禮上野揪,老公的妹妹穿的比我還像新娘访忿。我一直安慰自己,他們只是感情好斯稳,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布海铆。 她就那樣靜靜地躺著,像睡著了一般挣惰。 火紅的嫁衣襯著肌膚如雪卧斟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天憎茂,我揣著相機與錄音珍语,去河邊找鬼。 笑死唇辨,一個胖子當著我的面吹牛廊酣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赏枚,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼亡驰,長吁一口氣:“原來是場噩夢啊……” “哼晓猛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起凡辱,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤戒职,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后透乾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洪燥,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年乳乌,在試婚紗的時候發(fā)現(xiàn)自己被綠了捧韵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡汉操,死狀恐怖再来,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磷瘤,我是刑警寧澤芒篷,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站采缚,受9級特大地震影響针炉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扳抽,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一篡帕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摔蓝,春花似錦赂苗、人聲如沸愉耙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朴沿。三九已至猜谚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赌渣,已是汗流浹背魏铅。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坚芜,地道東北人览芳。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像鸿竖,于是被迫代替她去往敵國和親沧竟。 傳聞我的和親對象是個殘疾皇子铸敏,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350