MySQL的事務(wù)隔離級別

前言

沒什么前言展辞,直接開始吧媳叨!
主要想從下面三個方面說一下事務(wù)隔離級別:

  1. 為什么會出現(xiàn)事務(wù)隔離級別蕉朵。
  2. 事務(wù)隔離級別的種類崔涂。
  3. 如何實現(xiàn)事務(wù)隔離級別

為什么會出現(xiàn)事務(wù)隔離級別?

事務(wù)隔離隔離級別始衅,顧名思義冷蚂,就是事務(wù)的隔離級別,主要服務(wù)對象就是事務(wù)汛闸。
事務(wù)在高并發(fā)的情況下會暴露很多問題蝙茶,主要有三種:

  1. 臟讀
    一個事務(wù)讀取到另一個事務(wù)未提交的數(shù)據(jù),別的行未提交的數(shù)據(jù)也叫臟數(shù)據(jù)诸老,所以叫臟讀隆夯。
  2. 不可重復(fù)讀
    在同一個事務(wù)中多次讀取同一個數(shù)據(jù),出現(xiàn)數(shù)據(jù)不一致别伏,重復(fù)讀取出現(xiàn)問題蹄衷,所以叫不可重復(fù)讀
    不可重復(fù)度可以看做臟讀的升級版本厘肮,讀到了別的事務(wù)已提交的數(shù)據(jù)愧口。
  3. 幻讀
    在同一個事務(wù)中多次讀取一定范圍內(nèi)的數(shù)據(jù),出現(xiàn)數(shù)據(jù)行不一致的情況类茂,像是出現(xiàn)幻覺一樣耍属,所以叫幻讀
    幻讀在不可重復(fù)讀的基礎(chǔ)上再上升了一檔大咱,不但當前行數(shù)據(jù)出現(xiàn)了不一致恬涧,查找范圍內(nèi)也出現(xiàn)了不一致注益。

這里比較難區(qū)分的是不可重復(fù)讀和幻讀碴巾,記住它們兩個針對對象不一致即可。

  • 不可重復(fù)讀針對的主要是單行內(nèi)的數(shù)據(jù)丑搔,比如在同一個事務(wù)中讀取id為1的name為a厦瓢,過一段時間再讀取id為1的name卻變?yōu)閎了,就是不可重復(fù)讀啤月。
  • 幻讀針對的主要是一定范圍內(nèi)的數(shù)據(jù)煮仇,比如在同一個事務(wù)中讀取id大于1但小于10的數(shù)據(jù)只有三條數(shù)據(jù),過一段時間再讀取這個范圍卻變成四條數(shù)據(jù)谎仲,就是幻讀浙垫。

MySQL是一款支持并發(fā)的數(shù)據(jù)庫軟件,肯定要解決上面的問題的啊,所以就衍生出了事務(wù)隔離這種東西夹姥,針對不同的問題杉武,對事務(wù)隔離又分了級,就是事務(wù)隔離級別

事務(wù)隔離級別的種類

針對上面的三個問題辙售,數(shù)據(jù)庫中存在四種事務(wù)隔離級別

  1. 未提交讀(READ_UNCOMMITTED)
    最低的事務(wù)隔離級別轻抱,臟讀都不能避免。
  2. 已提交讀(READ_COMMITED)
    在這個隔離級別下可以避免臟讀旦部,但不能避免不可重復(fù)讀祈搜。
  3. 可重復(fù)讀(REPEATABLE_READ)
    在這個隔離級別下可以避免不可重復(fù)讀,但不能避免幻讀士八。
  4. 串行化(SERLALIZABLE)
    最高的隔離級別容燕,可以避免并發(fā)產(chǎn)生的問題。
事務(wù)隔離級別 避免臟讀 避免不可重復(fù)讀 避免幻讀
未提交讀 × × ×
已提交讀 × ×
可重復(fù)讀 ×
串行化

(在InnoDB中有點特殊婚度,可重復(fù)讀級別也能在一定程度上避免幻讀)
天下沒有免費的午餐缰趋,越高的隔離級別在進行操作時開銷越大,支持的并發(fā)越低陕见,為了針對不同的業(yè)務(wù)場景秘血,MySQL才會對其進行分級。


各隔離級別特性不需要硬記评甜,從中文命名上基本上都能看出來灰粮。


事務(wù)隔離級別如何實現(xiàn)

這里說的是InnoDB事務(wù)隔離級別的實現(xiàn),畢竟InnoDB是MySQL中支持事務(wù)最優(yōu)秀的存儲引擎


未提交讀

這個沒什么好說的忍坷,基本沒采取什么措施粘舟。不過支持的并發(fā)度最高,在不更新數(shù)據(jù)的時候用這個隔離級別是非常不錯的選擇佩研。


已提交讀和可重復(fù)讀

這兩個可以放在一塊說柑肴,因為實現(xiàn)的原理差不多。


有鎖經(jīng)驗的可能能想到旬薯,直接對查詢的數(shù)據(jù)行使用共享鎖不就可以防止臟讀和不可重復(fù)讀的問題了嗎晰骑?的確,直接對數(shù)據(jù)行使用行鎖能有效的避免臟讀和不可重復(fù)讀的問題绊序,但是這也就限制了其他想要修改這行數(shù)據(jù)的事務(wù)硕舆。
可能有些人想問了,你想避免臟讀和不可重復(fù)讀不鎖住行怎么行骤公?InnoDB就是想不鎖住行抚官,還把問題給解決了。
如何在不鎖住行的情況下還能避免臟讀呢阶捆?這就涉及到兩個概念:當前讀快照讀凌节。這兩個可以這樣理解:

  • 當前讀:就是上面上鎖的思想钦听,讀取數(shù)據(jù)時順便將數(shù)據(jù)行加鎖,使其它事務(wù)不能修改數(shù)據(jù)倍奢,自然不會產(chǎn)生臟讀和不可重復(fù)讀的情況彪见。
  • 快照讀:和名字一樣,就是對數(shù)據(jù)進行進行一次快照讀取數(shù)據(jù)中的內(nèi)容娱挨。因為不需要加鎖余指,又叫非阻塞讀。
    為了能支持更高的并發(fā)跷坝,已提交讀和可重復(fù)讀的隔離級別select只要沒有顯式加鎖(顯式加鎖:select * from TABLE lock in share mode)酵镜,采用的就是快照讀。只不過采用的策略不一樣.
  • 已提交讀每次讀取都到特定事務(wù)版本的數(shù)據(jù)柴钻,沒有提交的數(shù)據(jù)不會對這兒的數(shù)據(jù)造成影響淮韭,這樣避免了臟讀的發(fā)生。
  • 可重復(fù)讀對特定事務(wù)版本的數(shù)據(jù)進行快照之后贴届,會將讀取到的數(shù)據(jù)快照保存在了另一個地方靠粪,讀取讀取過的數(shù)據(jù)就會從這個地方中讀取(不是口胡毫蚓,有點繞)占键。因為事務(wù)提交也不會對另存的地方造成影響,這樣就避免了不可重復(fù)讀的發(fā)生元潘。
    (可以理解為對數(shù)據(jù)做了一個備份畔乙,備份與原數(shù)據(jù)沒有太大的關(guān)聯(lián),但注意的是不是將所有數(shù)據(jù)都做一個備份翩概,那樣需要耗費的空間太大牲距,只是將查詢過的數(shù)據(jù)行進行備份,比如查詢id為1的數(shù)據(jù)行钥庇,并不會對id為2的數(shù)據(jù)行進行備份)

快照的實現(xiàn)原理主要涉及以下幾個概念牍鞠,這里就不展開來講了。

  1. 數(shù)據(jù)行中的DB_TRX_ID评姨、DB_ROLL_PTR难述、DB_ROW_ID
    • DB_TRX_ID:事務(wù)id,InnoDB中事務(wù)都有一個id参咙,這個id是遞增的龄广,和事務(wù)開啟的時間有關(guān)系硫眯。也就是說蕴侧,越早開始的事務(wù)這個id越小。
    • DB_ROLL_PTR:回滾指針两入,記錄著事務(wù)開始的時候在undo日志的位置净宵。
    • DB_ROW_ID:行號。
  2. undo日志
    當我們對數(shù)據(jù)做了變更操作的時候,就會產(chǎn)生undo記錄择葡,undo記錄的集合就是undo日志紧武。
    undo中記錄的都是更改之前的數(shù)據(jù),當我們需要提取事務(wù)開始之前的數(shù)據(jù)時敏储,就需要到undo日志中去查找阻星。
  3. read view
    read view是事務(wù)開啟時,當前所有事務(wù)的一個集合已添。
可重復(fù)讀級別下的幻讀的防止

InnoDB使用next-key鎖保證防止幻讀的產(chǎn)生妥箕。


next-key鎖可以看成由行鎖Gap鎖兩部分組成。行鎖不用說了更舞,主要說下Gap鎖畦幢。


Gap鎖

又稱間隙鎖,顧名思義缆蝉,就是針對間隙的鎖宇葱。使用Gap鎖的時候是會對數(shù)據(jù)周圍的間隙鎖住。這個間隙與數(shù)據(jù)有關(guān)刊头。比如果數(shù)據(jù)中有:1黍瞧、3、5原杂、7雷逆、9五個數(shù)據(jù),那么就可以對下面幾個間隙進行鎖定:

(-oo, 1]污尉、(1, 3]膀哲、(3, 5]、(5, 7]被碗、(7, 9]某宪、(9, +oo]

比如你查詢3這個數(shù)據(jù)行,那么這個事務(wù)未提交前其他事務(wù)就不能添加大于1小于等于5的數(shù)據(jù)(假設(shè)這個數(shù)據(jù)不是主鍵或唯一索引锐朴,主鍵或唯一索引有些特別兴喂,待會說)。添加值為4的數(shù)據(jù)行就會被阻塞住焚志。


查詢主鍵和唯一索引會不會使用Gap鎖還得看情況衣迷,主要有兩種情況:

  • 如果where條件全部命中,則不會用Gap鎖酱酬,只會加記錄鎖壶谒。
    全部命中:精確查詢時所有記錄都存在。
  • 如果where部分命中或者全部不命中膳沽,則會加上Gap鎖汗菜。

這也是為了性能考慮让禀,加鎖總是得付出代價的,能不加就不加陨界。

為什么主鍵或唯一索引where條件全部命中可以不用加Gap鎖呢巡揍?
如果全部命中,InnoDB就會對數(shù)據(jù)加上記錄鎖菌瘪,這個事務(wù)提交前別的事務(wù)不能刪除這些行腮敌。因為是唯一索引,所以也不可能添加一樣的數(shù)據(jù)俏扩,所以使用記錄鎖完全滿足條件缀皱。

串行化

這個是最高的隔離級別,所有的select采用的都是當前讀动猬,都會對數(shù)據(jù)上行鎖啤斗。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赁咙,隨后出現(xiàn)的幾起案子钮莲,更是在濱河造成了極大的恐慌,老刑警劉巖彼水,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崔拥,死亡現(xiàn)場離奇詭異,居然都是意外死亡凤覆,警方通過查閱死者的電腦和手機链瓦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盯桦,“玉大人慈俯,你說我怎么就攤上這事∮德停” “怎么了贴膘?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長略号。 經(jīng)常有香客問我刑峡,道長,這世上最難降的妖魔是什么玄柠? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任突梦,我火速辦了婚禮,結(jié)果婚禮上羽利,老公的妹妹穿的比我還像新娘宫患。我一直安慰自己,他們只是感情好铐伴,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布撮奏。 她就那樣靜靜地躺著俏讹,像睡著了一般当宴。 火紅的嫁衣襯著肌膚如雪畜吊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天户矢,我揣著相機與錄音玲献,去河邊找鬼。 笑死梯浪,一個胖子當著我的面吹牛捌年,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挂洛,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼礼预,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了虏劲?” 一聲冷哼從身側(cè)響起托酸,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柒巫,沒想到半個月后励堡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡堡掏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年应结,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泉唁。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹅龄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亭畜,到底是詐尸還是另有隱情砾层,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布贱案,位于F島的核電站肛炮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宝踪。R本人自食惡果不足惜侨糟,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘩燥。 院中可真熱鬧秕重,春花似錦、人聲如沸厉膀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至凳兵,卻和暖如春百新,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背庐扫。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工饭望, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人形庭。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓铅辞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萨醒。 傳聞我的和親對象是個殘疾皇子斟珊,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容