眾所周知,Mysql在InnoDB下有四種隔離級(jí)別:

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比紅旗網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式紅旗網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋紅旗地區(qū)。費(fèi)用合理售后完善,10年實(shí)體公司更值得信賴。
未提交讀(Read Uncommitted)
提交后讀(Read Committed)
可重復(fù)讀(Repeatable Read)
串行化(Serializable)
其中可重復(fù)讀(RR)可以避免臟讀( a事務(wù)讀到b事務(wù)回滾前的數(shù)據(jù))以及可不重復(fù)讀( a事務(wù)在b事務(wù)修改提交的前后,兩次分別讀到的數(shù)據(jù)不一致)。但是對(duì)于幻讀(a事務(wù)在b事務(wù)insert提交前后,兩次分別讀到的數(shù)據(jù)不一致),卻存在爭議。
下面我們來做一個(gè)試驗(yàn):
對(duì)于下面這張簡單的數(shù)據(jù)表
id? ? ? ? num
1 ????????11
2 ????????22
3 ????????33
我們開啟a、b兩個(gè)事務(wù)
a事務(wù)? ? ? ? ? ? ????b事務(wù)
begin? ? ? ? ? ? ????begin
select * from tb? ? ----
----? ? ? ? ? ? ? ? ? ? insert into tb (id,num)values(4,44)
----? ? ? ? ? ? ? ? ? ? commit
select * from tb? ? ----
commit
試驗(yàn)結(jié)果:a事務(wù)的兩次select查詢到的結(jié)果相同,在后一次查詢中沒有返回新插入id=4的那條記錄。
據(jù)此,很多人判斷說RR隔離級(jí)別下“不存在”幻讀。
但果真如此嗎?----
出現(xiàn)上面的試驗(yàn)結(jié)果,是因?yàn)樵赗R隔離級(jí)別事務(wù)下,Mysql會(huì)對(duì)前一次select的結(jié)果快照。所以第二次select其實(shí)是快照讀(這也正是RR隔離級(jí)別下能夠避免不可重復(fù)讀的策略)。
如果我們把試驗(yàn)條件稍作修改,同樣開啟a、b兩個(gè)事務(wù):
a事務(wù)? ? ? ? ? ? ????b事務(wù)
begin? ? ? ? ? ? ????begin
select * from tb? ? ----
----? ? ? ? ? ? ? ? ? ? insert into tb (id,num)values(5,55)
----? ? ? ? ? ? ? ? ? ? commit
update tb set num=num+1? ? ----? ? ? ? #此處a事務(wù)做一次修改操作
select * from tb? ? ----
commit
試驗(yàn)結(jié)果:在a事務(wù)的第二次select中出現(xiàn)了b事務(wù)新插入的id=5的記錄。
由于做了update操作,之前的快照失效了,所以說RR隔離級(jí)別下的快照策略并沒能真正避免幻讀。
ps. 假如給第二次的select查詢上鎖(無論是共享鎖還是排它鎖),也會(huì)得到同樣的結(jié)果,都會(huì)令快照失效。
見圖,主要是select xx for update,又或者是update語句更新了,使用了當(dāng)前讀。所以后面再次select(13行)出現(xiàn)幻讀,如果只是select的話(10行不是update,是個(gè)select),是不會(huì)出現(xiàn)幻讀的情況,因?yàn)榉蟤vcc規(guī)則,用的還是一開始的快照。
todo:看下10行是update的情況下的內(nèi)容:SELECT * FROM information_schema . INNODB_TRX
如果10行,update的id為1,則不會(huì)出現(xiàn)幻讀的情況,這里因?yàn)閡pdate的時(shí)候把session2里的更新到了
幻讀的定義是指,一個(gè)事務(wù)開啟后,執(zhí)行前后兩次查詢,兩次查詢中出現(xiàn)了新的數(shù)據(jù),幻讀僅針對(duì)數(shù)據(jù)的新增。
比如: 表t中,id為主鍵,目前有數(shù)據(jù)1,5,10,20四條。
開始一個(gè)事務(wù)A,前后兩次執(zhí)行 select * from t where id 10 for update;
開啟一個(gè)事務(wù)B,在事務(wù)A第二次執(zhí)行查詢前,執(zhí)行insert into t values( 2,...); 并提交事務(wù)(請(qǐng)暫時(shí)忽略這里能否成功執(zhí)行!)。
此時(shí)在RC、RR隔離級(jí)別下都會(huì)導(dǎo)致事務(wù)A第二次查詢能夠查詢到 事務(wù)B新增的數(shù)據(jù) id = 2。
RC級(jí)別下能夠看到不同結(jié)果就不做解釋了。
對(duì)于RR隔離級(jí)別下,有了MVCC版本控制為什么還能讀取到不同的結(jié)果呢?
這里要?dú)w功于 "for update"。
"for update" 會(huì)將快照讀變?yōu)楫?dāng)前讀,在當(dāng)前讀場景中,會(huì)自動(dòng)讀取最新的數(shù)據(jù),而非快照數(shù)據(jù)。
分析一下,鎖與當(dāng)前讀關(guān)系。了解什么情況下會(huì)加鎖。了解 意向鎖、共享鎖、排它鎖區(qū)別及各自在什么情況下使用。
行鎖的概念都清楚,這里就不做補(bǔ)充了。
間隙鎖實(shí)際上是指一個(gè)區(qū)間。
我們都知道,InnoDB 在RR事務(wù)隔離級(jí)別下解決幻讀問題就是通過Next Key Lock (間隙鎖+行鎖)來實(shí)現(xiàn)的。而且,很多地方也有提到,如果對(duì)于讀一致性要求不高的場景可以考慮使用RC隔離級(jí)別,允許幻讀的發(fā)生。
還是上邊說的那個(gè)實(shí)例,略微改動(dòng):
比如: 表t中,id為主鍵,目前有數(shù)據(jù)1,5,10,20四條。
開始一個(gè)事務(wù)A,前后三次分別執(zhí)行
開啟一個(gè)事務(wù)B,在事務(wù)A執(zhí)行update前,執(zhí)行insert into t values( 2,...); 并提交事務(wù)。
此時(shí)我們知道,事務(wù)A中第二次查詢能夠查到 事務(wù)B新增的數(shù)據(jù),也就是產(chǎn)生了幻讀。那么,按照SQL執(zhí)行的順序來說,事務(wù)B
什么是幻讀?
幻讀指的是一個(gè)事務(wù)在前后兩次查詢同一個(gè)范圍的時(shí)候,后一次查詢看到了前一次查詢沒有看到的行。
首先快照讀是不存在幻讀的,只有當(dāng)前讀(實(shí)時(shí)讀)才存在幻讀的問題。
幻讀有什么問題?
select ...for update語句就是將相應(yīng)的數(shù)據(jù)行鎖住,但是如果存在幻讀,就把for update的語義破壞了。
如何解決幻讀?
產(chǎn)生幻讀的原因是,行鎖只能鎖住行,但是新插入記錄這個(gè)動(dòng)作,要更新的是記錄之間的“間隙”。因此,為了解決幻讀問題,InnoDB只好引入新的鎖,也就是間隙鎖(Gap Lock)。間隙鎖和行鎖合稱 next-key lock , 每個(gè)next-key lock是前開后閉區(qū)間 。
總結(jié)
當(dāng)前文章:linux提權(quán)命令ch,linux提權(quán)方式
URL地址:http://chinadenli.net/article14/dsgghde.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、面包屑導(dǎo)航、網(wǎng)站改版、Google、商城網(wǎng)站、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)