InnoDB隔離級別

數(shù)據(jù)庫隔離級別分為RU, RC, RR, Serialisable.以mysql 的InnoDB為例, 講解一下數(shù)據(jù)庫的隔離級別的原理是什么.

數(shù)據(jù)庫實(shí)現(xiàn)隔離級別主要還是通過兩個技術(shù)MVCC(多版本并發(fā)控制)和鎖. 不同的隔離級別, MVCC的版本生成時機(jī)不同, 鎖的范圍和釋放鎖的時機(jī)也不同,就造成了不同的隔離級別.

首先我們來了解一下什么是MVCC和鎖

基礎(chǔ)知識

幾種現(xiàn)象

我們先了解一下幾個讀現(xiàn)象: 臟讀, 不可重復(fù)讀, 幻讀

臟讀

臟讀是指一個事務(wù)A能夠讀到另一個事務(wù)B還未提交的操作.這里的問題是如果事務(wù)B發(fā)生了Rollback顯然會造成異常. 這是應(yīng)該避免的一種錯誤現(xiàn)象.

不可重復(fù)讀

不可重復(fù)讀指的是, 事務(wù)中一條數(shù)據(jù)被重復(fù)讀取的結(jié)果不一致. 假設(shè)如果有兩個事務(wù)A, B并發(fā)執(zhí)行. 事務(wù)A能夠讀取到事務(wù)B提交修改后的數(shù)據(jù).這個現(xiàn)象針對的是update, delete操作

幻讀

幻讀指的是, 兩個事務(wù)A, B并發(fā)執(zhí)行, 事務(wù)A能夠讀取到事務(wù)B中新增的數(shù)據(jù). 舉個例子, 事務(wù)A執(zhí)行select * from users where age > 0 and aget < 18;返回的結(jié)果是10條記錄. 同時事務(wù)B執(zhí)行insert into users(name, age) values('allen', 15);事務(wù)A再執(zhí)行相同的select語句將會得到11條記錄, 這就是幻讀.

MVCC

多版本并發(fā)控制, 顧名思義就是在高并發(fā)的情況下, 數(shù)據(jù)庫存在多個版本數(shù)據(jù)的情況.這個功能在mongoDB和HBase中都提供.如果沒有提供MVCC的功能, 一個事務(wù)想要讀取另一個事務(wù)正在修改的數(shù)據(jù)行的時候只能互斥等待, 這個時候并發(fā)能力就下降了, 而MVCC可以通過兩種方式去構(gòu)建出一個歷史版本的數(shù)據(jù).

  • 實(shí)時保留數(shù)據(jù)的一個或多個版本
  • 通過undo日志來構(gòu)建版本

數(shù)據(jù)庫的鎖

首先我們要了解一個概念, 就是數(shù)據(jù)庫的鎖并不是加在數(shù)據(jù)行上面而是加在索引行上面的.
接著我們來了解一下, 什么情況下會加鎖. 在一般修改數(shù)據(jù)記錄的情況下就會觸發(fā)加鎖的操作比如insert, delete, update, 注意我們剛剛說過了加鎖是加在索引行上面的, 如果這些操作沒有走索引是不會加行級鎖的而是加表級鎖. 而select需要顯示聲明的情況下才會觸發(fā)加鎖操作:

  • select * from users where id = 1; // 不加鎖
  • select * from users where id = 1 for update; // 加排它鎖
  • select * from users where id = 1 lock in share mode; // 加共享鎖

鎖的分類

  • Share and Exclusive Locks: 共享鎖相當(dāng)于一種JAVA的讀鎖, 讀不會上鎖, 但是讀寫, 寫寫操作是互斥的.Exclusive loc則是一種排它鎖, 都是互斥的.
  • Record Locks: 行級鎖, 之前說過鎖是加在索引行上的, 這個就是加在固定的索引行上加鎖.比如: select * from users where id = 1 and id = 10 for update; 就是在id = 1和id=10的索引行上面加鎖. 需要注意的是, 如果執(zhí)行select * from users where name = 'allen' for update; 如果name列上沒有加索引, 那么就會觸發(fā)表鎖, 會鎖住全表
  • Gap Locks: 間隙鎖, 它會鎖住兩個索引之間的區(qū)域, 比如select * from users where id > 1 and id < 10 for update; 那么會id在(1, 10)的索引區(qū)間加上鎖.
  • Next-key Locks: 也是一種間隙鎖, Gap Locks配合Record Locks形成一個閉區(qū)間的鎖, 比如select * from users where id >= 1 and id <= 10;

四種隔離機(jī)制

隔離級別 臟讀 不可重復(fù)讀 幻讀
Read Uncommit yes yes yes
Read Commited no yes yes
Read Repeatable no no yes
Serialisable no no no

Read Uncommit

這個模式下, 數(shù)據(jù)在發(fā)生修改以后就會釋放鎖, 而不是等到事務(wù)提交以后才釋放鎖. 這就導(dǎo)致各種問題, 會出現(xiàn)臟讀, 更別提幻讀了.

Read Commited

這個時候的鎖是在事務(wù)提交以后釋放的, 我們之前說過事務(wù)中的寫操作是需要上鎖的, 所以在釋放鎖之前讀也讀不到才對呀(事務(wù)中的讀使用排它鎖),一個事務(wù)能夠讀取到另一個事務(wù)提交以后的變更, 這是為什么呢?

謎底就是因?yàn)槭褂肕VCC, MVCC的出現(xiàn)使得能夠獲取到最新版本的數(shù)據(jù)快照, 也就是說讀出來的數(shù)據(jù)實(shí)際是通過MVCC機(jī)制構(gòu)建出來的, 這里就不存在鎖的問題.那么由于使用了MVCC, 也就是說重復(fù)執(zhí)行select能夠得到最新版本的數(shù)據(jù)快照, 也就是說能夠讀取到別的事務(wù)提交以后的最新變更, 這就導(dǎo)致了不可重復(fù)讀的問題.

此外Read Commited還存在幻讀的問題, 這是因?yàn)闆]有用間隙鎖, 比如事務(wù)A中執(zhí)行 select * from users where age > 10 and age < 18 for update; 一旦事務(wù)B中insert一條age=15的數(shù)據(jù), 那么事務(wù)A可以讀到這個新增的數(shù)據(jù), 這就是幻讀.

Read Repeatable

可重復(fù)讀, 這個模式改進(jìn)了一下所以可以在不可重復(fù)讀和避免幻讀都進(jìn)行了規(guī)避.

  1. 通過MVCC機(jī)制從事務(wù)開始時select獲取最新版本的數(shù)據(jù), 事務(wù)進(jìn)行中的所有select都是用這個版本的數(shù)據(jù), 所以能夠保證可重復(fù)讀
  2. 鎖范圍調(diào)整, 在行鎖的基礎(chǔ)上添加了Gap Locks形成next-key locks, 在遍歷過的索引行范圍內(nèi)都能夠進(jìn)行上鎖, 從而阻塞其他事務(wù)往這個范圍內(nèi)insert數(shù)據(jù), 避免幻讀

Serialisable

串行化, 會自動將所有的select都轉(zhuǎn)化成select lock in share mode執(zhí)行, 也就是針對所有的讀寫操作都會加鎖, 可靠性加強(qiáng), 但是并發(fā)度大大降低.

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

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

  • 我們都知道事務(wù)的幾種性質(zhì),數(shù)據(jù)庫為了維護(hù)這些性質(zhì),尤其是一致性和隔離性,一般使用加鎖這種方式。同時數(shù)據(jù)庫又是個高并...
    流浪冰007閱讀 1,131評論 0 2
  • 轉(zhuǎn)載自: https://tech.meituan.com/innodb-lock.html 前言:我們都知道事務(wù)...
    檀文淵閱讀 529評論 0 0
  • 秋夕月明時,有絲竹之音,往來神女峰峰頂,山猿聞之皆鳴,達(dá)旦方漸止。這是懷王拜月后,巫山上第一次不眠不休的盛會。 神...
    薛紫夜閱讀 3,272評論 35 86
  • 有關(guān)于孩子害怕什么,跟5歲兒子做了一個測驗(yàn),顛覆了家長的預(yù)期,同上一輩人小時候害怕的東西還真的不一樣呢!究竟是為什...
    塵世小書蟲閱讀 228評論 0 0

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