|
MySql數(shù)據(jù)庫(kù)——事務(wù)隔離級(jí)別和鎖關(guān)系學(xué)習(xí)
引言: 對(duì)于事務(wù)來(lái)說(shuō),有四種隔離級(jí)別,本文通過(guò)對(duì)多篇博客的理解和匯總,加上實(shí)際的效果展示和個(gè)人理解,對(duì)MySql四種事務(wù)隔離級(jí)別和鎖進(jìn)行分析。
一.事務(wù)隔離級(jí)別: 事務(wù)具有ACID屬性,而事務(wù)的隔離級(jí)別可以不同程度的解決事務(wù)并發(fā)時(shí)可能產(chǎn)生的問(wèn)題,可以根據(jù)不同業(yè)務(wù)邏輯需求,來(lái)選擇不同的事務(wù)隔離等級(jí),事務(wù)隔離等級(jí)越高,越能保證數(shù)據(jù)的一致性,但就更趨近于串行化,降低并發(fā)性能,導(dǎo)致效率變低。 四種事務(wù)隔離級(jí)別: 未提交讀(RU) 已提交讀(RC) 可重復(fù)讀(RR) 序列化/串行化(Serializable) 這四種隔離級(jí)別可以在不同程度上解決事務(wù)在并發(fā)時(shí)產(chǎn)生的問(wèn)題——臟讀,不可重復(fù)讀,幻讀。 1.臟讀:有AB兩個(gè)事務(wù),B事務(wù)對(duì)一條數(shù)據(jù)進(jìn)行修改,但未提交;而A事務(wù)在這之后對(duì)同一條數(shù)據(jù)進(jìn)行讀操作,讀到的若是未提交的修改后的數(shù)據(jù),就說(shuō)明產(chǎn)生了臟讀現(xiàn)象。 2.不可重復(fù)讀:有一個(gè)A事務(wù)和若干其他事務(wù),A事務(wù)對(duì)一條數(shù)據(jù)(或多條符合同一查詢條件的數(shù)據(jù))進(jìn)行多次的讀操作;其他的事務(wù)對(duì)A事務(wù)所讀的數(shù)據(jù)進(jìn)行了修改(這里不包括插入新的數(shù)據(jù)),若是未提交,在RU級(jí)別可以讀到修改的數(shù)據(jù),若是已提交,在RC級(jí)別及以下可以讀到修改的數(shù)據(jù);那么這種情況就可能會(huì)導(dǎo)致A事務(wù)在多次讀取數(shù)據(jù)的時(shí)候,發(fā)現(xiàn)讀取的數(shù)據(jù)值不一致,這種現(xiàn)象被稱為不可重復(fù)讀。 3.幻讀:幻讀的概念在網(wǎng)上很難找到一個(gè)全面且完全正確的解釋,這里的解釋是我個(gè)人的理解,可能會(huì)有偏差。 幻讀大致上有兩種情況: 幻讀情況1:同樣的查詢語(yǔ)句,前后兩次讀取,發(fā)現(xiàn)數(shù)據(jù)量的個(gè)數(shù)發(fā)生了改變。(RU,RC級(jí)別不能解決這個(gè)問(wèn)題,RR和序列化可以解決這個(gè)問(wèn)題) 幻讀情況2:第二種情況中還可以分為兩種情況一,有AB兩個(gè)事務(wù),A事務(wù)按某個(gè)條件查詢數(shù)據(jù),B事務(wù)在A事務(wù)查詢之后插入了一條符合A事務(wù)查詢條件的數(shù)據(jù),這里B事務(wù)提交與否的情況與不可重復(fù)讀的一致,在B事務(wù)做完操作后,A事務(wù)也想插入B事務(wù)剛才插入的數(shù)據(jù),但卻發(fā)現(xiàn)插入不成功,第一次沒(méi)有讀到的數(shù)據(jù),但卻插入不成功,這種情況即為幻讀;二,有AB兩個(gè)事務(wù),A事務(wù)按某個(gè)條件查詢數(shù)據(jù),B事務(wù)在A事務(wù)查詢之后,刪除了一條之前A事務(wù)查詢到的數(shù)據(jù),在B完成操作后,A事務(wù)也想把B剛才刪除的數(shù)據(jù)刪除掉,但發(fā)現(xiàn)影響的行數(shù)是0,明明查到了,但刪不掉,這種情況也是幻讀,并且在RR的隔離級(jí)別下,不僅影響行數(shù)為0,再查的時(shí)候,數(shù)據(jù)還依然存在,造成這種現(xiàn)象的原因是RR級(jí)別使用了快照讀(在下文會(huì)有解釋)。(RR隔離級(jí)別可以在一定程度上避免這種情況,序列化可完全避免)
二.鎖的概念: 1.按功能劃分: 共享鎖(讀鎖):有A事務(wù)對(duì)某數(shù)據(jù)加讀鎖,那么其他事務(wù)只可以讀這條數(shù)據(jù),但不能修改。 排他鎖(寫鎖):有事務(wù)A對(duì)某數(shù)據(jù)加寫鎖,那么只有A事務(wù)可以操作此數(shù)據(jù),別的事務(wù)既不能讀,更不能改。 其實(shí)還有兩種意向鎖,但本文內(nèi)容與意向鎖關(guān)聯(lián)不大,暫不作介紹。 2.按范圍劃分: 行鎖:mysql數(shù)據(jù)庫(kù)下的InnoDB引擎支持行鎖,鎖住一行數(shù)據(jù)。 表鎖:mysql數(shù)據(jù)庫(kù)下的MyISAM和InnoDB引擎都支持表鎖,鎖住一整張表。 頁(yè)鎖在這里不做介紹 3.按用途劃分: 樂(lè)觀鎖:樂(lè)觀鎖其實(shí)從實(shí)現(xiàn)的角度上,并沒(méi)有進(jìn)行加鎖的操作,而是使用版本號(hào),來(lái)控制數(shù)據(jù)的一致性,例如在提交修改的數(shù)據(jù)時(shí),會(huì)判斷這條修改的數(shù)據(jù)的版本號(hào)是否大于修改前的版本號(hào),若大于則修改。因?yàn)闃?lè)觀鎖沒(méi)有加鎖和解鎖的開銷,所以從效率上比較可觀,但是樂(lè)觀鎖的缺點(diǎn)是不可以跨應(yīng)用操作,所以就產(chǎn)生了悲觀鎖的概念。 悲觀鎖:悲觀鎖是真正的對(duì)需要操作的數(shù)據(jù)進(jìn)行了加鎖和解鎖的操作,來(lái)確保事務(wù)并發(fā)而帶來(lái)的問(wèn)題,雖然把數(shù)據(jù)鎖死可以減少錯(cuò)誤,但加鎖解鎖會(huì)加大開銷,效率會(huì)相應(yīng)下降。 三.事務(wù)隔離級(jí)別與鎖之間的關(guān)系: 這部分主要是介紹mysql中四種事務(wù)隔離級(jí)別是如何實(shí)現(xiàn)的,能解決那些并發(fā)問(wèn)題,以及使用了哪些鎖來(lái)實(shí)現(xiàn)這四種隔離界別。
在開始下面內(nèi)容之前,需要知道mysq中兩種不同的select方式: 快照讀:讀取的是記錄的歷史版本,在一個(gè)沒(méi)有結(jié)束的事務(wù)中,快照讀每次讀取的都和在本次事務(wù)中第一次讀到的信息一致(不加讀鎖)。 當(dāng)前讀:讀取的是記錄的最新版本(會(huì)加讀鎖)。
1.未提交讀(RU): 1.1實(shí)現(xiàn)機(jī)制: 事務(wù)在讀數(shù)據(jù)的時(shí)候采用當(dāng)前讀 事務(wù)在修改數(shù)據(jù)的時(shí)候加共享鎖,提交后釋放(解決了修改時(shí),數(shù)據(jù)被刪除或修改的情況) 1.2臟讀情況:會(huì)發(fā)生 首先是開啟分別開啟兩個(gè)會(huì)話,后續(xù)會(huì)用A事務(wù)和B事務(wù)來(lái)代指這兩個(gè)會(huì)話,然后把事務(wù)隔離級(jí)別設(shè)置為RU
以下操作按順序進(jìn)行: A事務(wù)查詢某表信息:
B事務(wù)插入新數(shù)據(jù),但不提交:
A事務(wù)再次查詢此表:讀到了B事務(wù)未提交的操作,臟讀情況發(fā)生 1.3不可重復(fù)讀情況:會(huì)發(fā)生 A事務(wù)查詢id為30的數(shù)據(jù):
B事務(wù)對(duì)id為30的數(shù)據(jù)進(jìn)行修改:提交與否不影響結(jié)果
A事務(wù)再次查詢id為30的數(shù)據(jù):與第一次讀的num數(shù)據(jù)值不同,不可重復(fù)讀情況發(fā)生
1.4幻讀情況:會(huì)發(fā)生 A事務(wù)查詢id<30的數(shù)據(jù):
B事務(wù)插入一條id<30的數(shù)據(jù):提交與否不影響結(jié)果
A事務(wù)再次查詢id<30的數(shù)據(jù):查到的數(shù)據(jù)比第一次多一條,幻讀情況1發(fā)生
2.已提交讀(RC): 2.1實(shí)現(xiàn)機(jī)制: 事務(wù)在讀數(shù)據(jù)的時(shí)候加讀鎖(當(dāng)前讀),讀完即釋放共享鎖 事務(wù)在修改某數(shù)據(jù)時(shí)會(huì)加上寫鎖,直到事務(wù)結(jié)束再釋放,這樣的機(jī)制保證了RC隔離級(jí)別不會(huì)發(fā)生臟讀,只有提交過(guò)的事務(wù),才能被其他事務(wù)看見 2.2臟讀情況:不會(huì)發(fā)生 首先是開啟分別開啟兩個(gè)會(huì)話,后續(xù)會(huì)用A事務(wù)和B事務(wù)來(lái)代指這兩個(gè)會(huì)話,然后把事務(wù)隔離級(jí)別設(shè)置為RC。
以下操作按順序進(jìn)行: A事務(wù)查詢某表信息:
B事務(wù)插入新數(shù)據(jù),但不提交:
A事務(wù)再次查詢此表:沒(méi)有讀到B事務(wù)插入的數(shù)據(jù),臟讀情況沒(méi)有發(fā)生
2.3不可重復(fù)讀情況:會(huì)發(fā)生 RC隔離級(jí)別下的不可重復(fù)讀的情況和RU是類似的,只是B事務(wù)在修改數(shù)據(jù)的時(shí)候,需要提交。 2.4幻讀情況:會(huì)發(fā)生 RC隔離級(jí)別下的幻讀的情況和RU是類似的,只是B事務(wù)在插入數(shù)據(jù)的時(shí)候,需要提交。
3.可重復(fù)讀(RR): 3.1實(shí)現(xiàn)機(jī)制:MVCC(Mysql下的InnoDB引擎為例) 事務(wù)在讀數(shù)據(jù)的時(shí)候采用的是快照讀(解決不可重復(fù)讀問(wèn)題) 事務(wù)在修改數(shù)據(jù)的時(shí)候加寫鎖,并且Mysql采用了間隙鎖,但觸發(fā)間隙鎖的前提是(查詢條件列不可以是唯一索引和主鍵),在觸發(fā)間隙鎖后,會(huì)鎖住一定范圍內(nèi)的數(shù)據(jù),防止在這范圍內(nèi)插入數(shù)據(jù),這個(gè)機(jī)制可以在一定程度上降低發(fā)生幻讀情況2的可能。 3.2臟讀情況:不會(huì)發(fā)生 首先是開啟分別開啟兩個(gè)會(huì)話,后續(xù)會(huì)用A事務(wù)和B事務(wù)來(lái)代指這兩個(gè)會(huì)話,然后把事務(wù)隔離級(jí)別設(shè)置為RR。
RR隔離級(jí)別下的臟讀的情況和RC一樣 3.3不可重復(fù)讀情況:不會(huì)發(fā)生 A事務(wù)查詢id為30的數(shù)據(jù):
B事務(wù)對(duì)id為30的數(shù)據(jù)進(jìn)行修改:修改后提交事務(wù)
A事務(wù)再次查詢id為30的數(shù)據(jù):與第一次讀的num數(shù)據(jù)值相同,沒(méi)有發(fā)生不可重復(fù)讀的情況
3.4幻讀情況:會(huì)發(fā)生幻讀情況2,不會(huì)發(fā)生幻讀情況1(雖然其他事務(wù)仍可能會(huì)insert數(shù)據(jù),但是由于RR采用了快照讀,所以不會(huì)讀到insert的數(shù)據(jù)) 幻讀情況2:會(huì)發(fā)生 A事務(wù)查詢?nèi)繑?shù)據(jù)
B事務(wù)插入一條新數(shù)據(jù):需要提交事務(wù)
A事務(wù)由于不知B事務(wù)插入過(guò)這條數(shù)據(jù),所以也想插入這條數(shù)據(jù):A事務(wù)會(huì)插入失敗,并且再次全部讀數(shù)據(jù)的時(shí)候,還沒(méi)有發(fā)現(xiàn)這條因?yàn)橹麈I約束而插入失敗的數(shù)據(jù),這樣的情況即發(fā)生了幻讀情況2。
幻讀情況2:會(huì)發(fā)生 A事務(wù)查詢?nèi)繑?shù)據(jù)
B事務(wù)刪除A事務(wù)查詢的數(shù)據(jù)中的一條:需要提交事務(wù)
A事務(wù)由于不知B事務(wù)刪除過(guò)這條數(shù)據(jù),所以也想刪除這條數(shù)據(jù):A事務(wù)刪除語(yǔ)句執(zhí)行后,會(huì)發(fā)現(xiàn)影響的行數(shù)為0,并且再次全部讀數(shù)據(jù)的時(shí)候,還發(fā)現(xiàn)這條數(shù)據(jù)沒(méi)有被刪除,這樣的情況也是發(fā)生了幻讀情況2。
3.5間隙鎖發(fā)生情況:若查詢列是上有索引(且不是唯一索引)且不為主鍵,則間隙鎖會(huì)觸發(fā)一定范圍的鎖,如下面的例子;若查詢列上沒(méi)有索引且不是主鍵,那么間隙鎖會(huì)為整張表上鎖 A事務(wù)查詢?nèi)繑?shù)據(jù):
A事務(wù)修改num=30的數(shù)據(jù)(num是普通索引),把name改為test:
B事務(wù)插入一條num=32的數(shù)據(jù):可以插入成功
B事務(wù)插入一條num=29的數(shù)據(jù):發(fā)現(xiàn)插入阻塞,造成這種現(xiàn)象的原因就是因?yàn)殚g隙鎖的作用,由于A事務(wù)以num=30的索引列為條件修改了數(shù)據(jù),所以間隙鎖把num=30兩端的范圍數(shù)據(jù)給鎖起來(lái)了,即num = (5,30),在這個(gè)范圍內(nèi)的數(shù)據(jù)都被上鎖了,注意這里都是開區(qū)間,在這個(gè)范圍外的數(shù)據(jù)可以被操作。
4.序列化(Serializable): 實(shí)現(xiàn)機(jī)制: 事務(wù)在讀取數(shù)據(jù)時(shí),對(duì)整個(gè)表加讀鎖,提交或回滾事務(wù)后釋放 事務(wù)在修改數(shù)據(jù)時(shí),對(duì)整個(gè)表加寫鎖,提交或回滾事務(wù)后釋放 這是最高的隔離級(jí)別,可以解決臟讀,不可重復(fù)讀和幻讀,但同時(shí)效率也是最差的一個(gè)。它解決這些由于事務(wù)并發(fā)帶了的問(wèn)題的方法就是把這些操作變成串行操作,一旦不符合條件,就會(huì)被阻塞,所以效率特別差。
參考博客: 虛擬WORLD-er:https://blog.csdn.net/qq_37960007/article/details/90644635?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-1-90644635.nonecase 三石雨:https://www.cnblogs.com/exceptioneye/p/5450874.html 李俊陽(yáng):https://www.cnblogs.com/ljy-skill/p/10622865.html 牛初九:https://www.cnblogs.com/boboooo/p/12370770.html#4506259 Luke:https://zhuanlan.zhihu.com/p/109414420 |
|
|