MySQL -- MVCC

前言

最近在學(xué)MySQL,決定記錄一下,能寫多少寫多少,不定時更新,加油。

正文

分幾個部分來吧,大致如下:

  • 字符集與比較規(guī)則

  • 行格式與數(shù)據(jù)頁

  • InnoDB索引

  • 訪問方法與連接

  • explain 與 子查詢優(yōu)化

  • redoundo 日志

  • MVCC 與 鎖

本文為第四部分 MVCC 原理解析


主要就是想先寫這個, 其他的后面有空再補~

由于我們跳過一些東西, 下面說MVCC的原理可能會各種懵


所以, 我們先簡單過幾個點吧.

一、溫故知新 -- 兩個隱藏列的含義

行格式的時候說過,InnoDB會為每行加上兩個隱藏列(row_id并不是必加的)trx_idroll_pointer 這倆哥們簡直生猛的一塌糊涂.

小聲明:
事務(wù)T1的編號是100
事務(wù)T2的編號是200

  • trx_id 這個明顯是事務(wù)ID的意思, 就是記錄一下最近操作此條記錄的事務(wù)ID. 比如事務(wù)T1中插入了一條記錄X,那X的trx_id就是100,如果在T1中繼續(xù)操作這條記錄是不會修改X的trx_id的.如果事務(wù)T2修改了這X記錄,那么其trx_id就變成200.
  • roll_pointer字面意思就是回滾指針, 指針存放的是一個地址, 指向了某個值. 它指向的是一條undo日志記錄.

這里簡單提一下undo日志,后面會專門寫一篇詳細講的[有生之年系列]。

一條undo日志就是一條記錄, 存放在頁中,叫undo日志頁.大致分為兩種,插入類型(insert)和修改類型(updatedelete),這里只需要知道他們有一個很大區(qū)別:插入類型的undo日志是沒有指向下一條undo日志的屬性的,也就是說他們組成了一個undo日志鏈表,又稱版本鏈。

undo日志鏈表(版本鏈)
  • 第一條是真實記錄,0是記錄類型,H是記錄頭,300是trx_id R是roll_pointer, 1、3.. 是記錄的真實數(shù)據(jù)
  • 可以看到每條undo日志都有一個事務(wù)ID(圖中我畫在最后面,實際并不是存在最后),這個屬性其實是叫old trx_id, 表示當(dāng)前undo日志對應(yīng)的事務(wù)ID,也稱此版本的創(chuàng)建事務(wù)ID
  • 插入類型undo日志沒有old roll_pointer指向上一條roll_pointer,因為它本來就是版本鏈的第一條
  • 這條undo鏈表可以看出,此記錄由事務(wù)ID為100的事務(wù)插入,在事務(wù)ID為200的事務(wù)中修改了兩次,而事務(wù)ID為300的事務(wù)正在修改此記錄。
  • 記住這個順序,后面有用。

二、老生常談 -- 隔離級別

說這個隔離級別之前,我們先想想為什么要有這個東東?

其實每個新技術(shù)或新名詞的出現(xiàn), 都可以問這幾個問題
1.這個東東解決了什么問題嗎?
2.現(xiàn)有的技術(shù)解決不了嗎?
3.如果能, 它比當(dāng)前的解決方案強在哪些方面呢?
4.不足或改進之處.

  • 以上純屬扯淡

隨著互聯(lián)網(wǎng)的發(fā)展,并發(fā)已經(jīng)是一道繞不開的坎。各種問題都不斷冒出來,那并發(fā)事務(wù)訪問數(shù)據(jù)庫會發(fā)生什么樣的問題呢?

一個一個來看下。

  • 臟寫(Dirty Write
    T1事務(wù)開啟
    T1修改:X=5
    T2事務(wù)開始
    T2修改:X=6
    T2事務(wù)提交
    T1事務(wù)提交

結(jié)果:X=5

這個時候T2的事務(wù)所做修改就丟失了.

一個事務(wù)修改了另一個未提交事務(wù)修改過的數(shù)據(jù),此為臟寫。

  • 臟讀(Dirty Read
    數(shù)據(jù)狀態(tài):X=5
    T1事務(wù)開啟
    T2事務(wù)開始
    T2修改:X=6
    T1讀?。篨=6
    T2事務(wù)回滾
    T1事務(wù)提交

T1讀到的X=6,庫中X=5

一個事務(wù)讀取了另一個未提交事務(wù)修改過的數(shù)據(jù),此為臟讀。

  • 不可重復(fù)讀(Non-Repeatable Read
    事務(wù)T1開啟
    事務(wù)T2開啟
    T1讀?。篨=5
    T2修改:X=6
    事務(wù)T2提交
    T1讀?。篨=6
    。。。

T1兩次讀取到的同一條記錄的值不一樣。

每次事務(wù)提交后,當(dāng)前事務(wù)都能讀取到記錄的最新值,此為不可重復(fù)讀。

  • 幻讀(Phantom
    庫中數(shù)據(jù): X=6
    事務(wù)T1開啟
    事務(wù)T2開啟
    T1讀?。篨>5 (得到一條X=6)
    T2新增:X=7
    T1讀?。篨>5 (得到兩條X=6和X=7)
    。。。

T1第二次讀取的記錄數(shù)量比第一次讀取到的記錄數(shù)量多。

如果事務(wù)T1根據(jù)條件N查詢數(shù)據(jù),事務(wù)T2添加了滿足條件N的記錄并提交了,T1再次根據(jù)N查詢數(shù)據(jù)能查詢T2新增的記錄,此為幻讀。

注意幾個點:

  • 不可重復(fù)讀是針對單條記錄的改動(包括刪除與修改)
  • 幻讀是針對查詢條件的范圍內(nèi)記錄的新增
  • 幻讀只是針對新增,如果有范圍內(nèi)記錄的刪除或修改,都屬于不可重復(fù)讀

為了解決這些問題,有一幫人提出了一個SQL標(biāo)準(zhǔn),給出了四種隔離級別,用以解決上訴問題:

  • READ UNCOMMITTED
  • READ COMMITTED
  • READ REPEATABLE
  • SERIALABLE

SQL標(biāo)準(zhǔn)中規(guī)定,

  • READ UNCOMMITTED 解決臟寫
  • READ COMMITTED 解決臟讀
  • READ REPEATABLE 解決臟讀與不可重復(fù)讀
  • SERIALABLE 解決幻讀

數(shù)據(jù)庫對臟寫的問題是零容忍,哪怕最低的隔離級別都不允許出現(xiàn)

然而MySQL里的大佬還是牛逼,他們在READ REPEATABLE 級別就已經(jīng)解決了幻讀問題。

實現(xiàn)一般有兩種方式,第一是加鎖,第二是MVCC。

實際上,二者都有用到.


三、千呼萬喚 -- MVCC的原理

ReadView登場

先看下其大致結(jié)構(gòu)

ReadView結(jié)構(gòu)
  • m_ids 存放當(dāng)前系統(tǒng)中活躍的事務(wù)集合
  • min_trx_idm_ids中最小的事務(wù)ID
  • max_trx_id 分配給下一個開啟事務(wù)的事務(wù)ID
  • creator_trx_id 創(chuàng)建此ReadView的事務(wù)ID

事務(wù)ID注意兩點:

  • 只有在對表中的記錄做改動時(執(zhí)行INSERT、DELETEUPDATE這些語句時)才會為事務(wù)分配事務(wù)id,否則在一個只讀事務(wù)中的事務(wù)id值都默認為0。
  • 按分配順序遞增

怎么突然蹦出來一個ReadView? 先看看怎么用.

如果你不是一條魚的話,應(yīng)該還記得前面說過,每條記錄都有一個版本鏈吧,當(dāng)一個事務(wù)要訪問某條記錄時,對著這個ReadView的操作是這樣的:

  • 判斷trx_idcreator_trx_id是否相等,是則意味著此版本正在被當(dāng)前事務(wù)操作,可以訪問
  • 判斷trx_id是否小于min_trx_id,表示此版本的生成事務(wù)已經(jīng)提交,可以訪問
  • 判斷trx_id是否大于等于max_trx_id,表示此版本的生成事務(wù)已經(jīng)提交,可以訪問
  • 判斷trx_id是否在m_ids中,若不在,則意味著此版本的創(chuàng)建事務(wù)已經(jīng)提交,可以訪問;若在,則表明此版本在創(chuàng)建ReadView時還在活動,不能訪問。

若無法訪問則順著版本鏈找下一個版本,如果到最后一個版本(也就是Insert的undo日志)仍無法訪問,那么此記錄對當(dāng)前事務(wù)不可見。

現(xiàn)在知道這玩意有多牛逼了吧~

那跟隔離級別有啥關(guān)系呢?

READ COMMITTEDREAD REPEATABLE 的最大區(qū)別就是生成ReadView的時機不一樣

  • READ REPEATABLE 事務(wù)開啟時生成
  • READ COMMITTED 每次查詢前生成

想想ReadView與其生成時機如何能解決臟讀/幻讀問題~


喊我來加班,到公司都寫完一篇MVCC了,還沒見到人~~~~[允悲]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是事務(wù) 事務(wù)是一條或多條數(shù)據(jù)庫操作語句的組合,具備ACID,4個特點。 原子性:要不全部成功,要不全部撤銷 隔...
    jiangmo閱讀 1,204評論 0 3
  • MVCC(Mutil-Version Concurrency Control),就是多版本并發(fā)控制。MVCC 是一...
    yes的練級攻略閱讀 1,691評論 2 2
  • MVCC: 1什么是MVCC? MVCC是一種多版本并發(fā)控制機制。 2 MVCC的作用? 鎖的開銷畢竟很大...
    機智的老劉明同志閱讀 1,056評論 0 3
  • 1.Mysql特點 可靠、事務(wù)、開源。 2.MySQL架構(gòu) 接入層,連接通信、權(quán)限驗證、連接池、線程管理 服務(wù)層,...
    不是明天閱讀 4,610評論 1 0
  • MVCC(Multi Version Concurrency Control的簡稱),代表多版本并發(fā)控制。與MVC...
    漿水面韭菜花閱讀 58,827評論 21 87

友情鏈接更多精彩內(nèi)容