從設(shè)計(jì)的角度上,為什么要設(shè)計(jì)出MVCC颅眶,且RC和RR的隔離級(jí)別到底有什么不同蜈出。
MVCC作用
MVCC使得大部分支持行鎖的事務(wù)引擎,不再單純的使用行鎖來進(jìn)行數(shù)據(jù)庫的并發(fā)控制涛酗,而是把數(shù)據(jù)庫的行鎖和行的版本號(hào)結(jié)合起來铡原,只需要很小的開銷,就可以實(shí)現(xiàn)非鎖定讀商叹。從而提高數(shù)據(jù)庫的并發(fā)性能眷蜈。
MVCC是采用無鎖的形式解決讀-寫沖突問題。這里的讀是指的快照讀沈自。即MVCC實(shí)現(xiàn)的快照讀W萌濉!枯途!
什么是MVCC
多版本并發(fā)控制(MVCC)是一種解決讀-寫沖突的無鎖并發(fā)控制忌怎。
每一行記錄都有兩個(gè)隱藏列:創(chuàng)建版本號(hào)和回滾指針籍滴。事務(wù)開啟后存在一個(gè)事務(wù)id。多個(gè)并發(fā)事務(wù)同時(shí)操作某行榴啸,不同的事務(wù)對(duì)該行update操作會(huì)產(chǎn)生多個(gè)版本孽惰,然后通過回滾指針組成undo log鏈。而MVCC的快照讀正是通過事務(wù)id和創(chuàng)建版本號(hào)從而實(shí)現(xiàn)的快照讀鸥印。
MVCC與隔離級(jí)別的關(guān)系
MVCC是為了解決讀-寫問題勋功。且通過不同的配置,也可以解決事務(wù)開啟后库说,快照讀不可重復(fù)讀的問題狂鞋。
不可重復(fù)讀:同一個(gè)事務(wù)中讀取某些數(shù)據(jù)已經(jīng)發(fā)生改變,或某些記錄已經(jīng)刪除潜的。
幻讀:一個(gè)事務(wù)按照相同的查詢條件重新讀取以前檢索過的數(shù)據(jù)骚揍,卻發(fā)現(xiàn)其他事務(wù)插入了滿足查詢條件的新數(shù)據(jù),這種現(xiàn)象被稱為幻讀啰挪。
RC和RR均實(shí)現(xiàn)了MVCC信不,但是為什么RR解決了RC不可重復(fù)讀的問題?
你可以這樣認(rèn)為亡呵,RC之所以有不可重復(fù)讀的問題抽活,只是因?yàn)殚_發(fā)者有意設(shè)置的(設(shè)置多種隔離級(jí)別,用戶可以根據(jù)情況設(shè)置)锰什。本來數(shù)據(jù)都提交到數(shù)據(jù)庫了酌壕,RC讀取出來也沒什么問題呀?況且Oracle數(shù)據(jù)庫本身的隔離級(jí)別就是RC歇由。
READ-COMMITTED(讀已提交)
讀已提交RC,在這一隔離級(jí)別下果港,可以在SQL級(jí)別做到一致性讀沦泌,每次SQL語句都會(huì)產(chǎn)生新的ReadView。這就意味著兩次查詢之間有別的事務(wù)提交了辛掠,是可以讀到不一致的數(shù)據(jù)的谢谦。
REPEATABLE-READ(可重復(fù)讀)
可重復(fù)讀RR,在第一次創(chuàng)建ReadView后萝衩,這個(gè)ReadView就會(huì)一直維持到事務(wù)結(jié)束回挽,也就是說,在事務(wù)執(zhí)行期間可見性不會(huì)發(fā)生變化猩谊,從而實(shí)現(xiàn)了事務(wù)內(nèi)的可重復(fù)讀千劈。
MVCC和間隙鎖
MVCC無鎖解決了讀-寫沖突的問題。并且解決了不可重復(fù)讀問題牌捷。從而實(shí)現(xiàn)了RC和RR兩個(gè)隔離級(jí)別墙牌。
而間隙鎖本質(zhì)上依舊是鎖涡驮,會(huì)阻塞兩個(gè)并發(fā)事務(wù)的執(zhí)行。
那么RR為什么還要進(jìn)入間隙鎖喜滨,難道僅僅為了解決幻讀的問題嗎捉捅?
注意:只有RR隔離級(jí)別才存在間隙鎖。
間隙鎖在一定程度上可以解決幻讀的問題虽风,但是間隙鎖的引入我覺得更多是為了處理binlog的statement模式的bug棒口。
mysql數(shù)據(jù)庫的主從復(fù)制依靠的是binlog。而在mysql5.0之前辜膝,binlog模式只有statement格式无牵。這種模式的特點(diǎn):binlog的記錄順序是按照數(shù)據(jù)庫事務(wù)commit順序?yàn)轫樞虻摹?/p>
當(dāng)不存在間隙鎖的情況下,會(huì)有如下的場(chǎng)景:
master庫有這么兩個(gè)事務(wù):
1内舟、事務(wù)a先delete id<6合敦,然后在commit前;
2验游、事務(wù)b直接insert id=3充岛,并且完成commit;
3耕蝉、事務(wù)a進(jìn)行commit崔梗;
此時(shí)binlog記錄的日志是:事務(wù)b先執(zhí)行,事務(wù)a在執(zhí)行(binlog記錄的是commit順序)
那么主庫此時(shí)表里面有id=3的記錄垒在,但是從庫是先插入再刪除蒜魄,從庫里面是沒有記錄的。
這就導(dǎo)致了主從數(shù)據(jù)不一致场躯。
為了解決這個(gè)bug谈为,所以RR級(jí)別引入了間隙鎖。