mysql的隔離級別并非是按照標(biāo)準(zhǔn)實(shí)現(xiàn)的究恤,作為從pg切過來的程序員還真是不太適應(yīng)袁余,這篇文章討論mysql隔離級別實(shí)現(xiàn)的,希望對大家能有幫助茂嗓。
什么是事務(wù)
事務(wù)是數(shù)據(jù)庫一組讀寫操作的集合钥勋,事務(wù)具有ACID四個特性炬转,原子性,一致性算灸,隔離性和持久性扼劈。
事務(wù)有四個隔離級別,分別是讀未提交菲驴,讀已提交测僵,可重復(fù)讀和串行化。
以上這些內(nèi)容相信熟悉傳統(tǒng)數(shù)據(jù)庫的人谢翎,對這些都很熟悉,接下來講的內(nèi)容可能有些人就不太了解了沐旨。
事務(wù)的實(shí)現(xiàn)方式
數(shù)據(jù)庫事務(wù)的實(shí)現(xiàn)方式主要有兩種:
- 基于鎖的森逮;
- 基于時間戳的,現(xiàn)在主流的實(shí)現(xiàn)就是基于時間戳的方式的一種磁携,就是大家熟悉的MVCC機(jī)制褒侧;
因?yàn)闄C(jī)制不同,所以事務(wù)的表現(xiàn)也不盡相同谊迄。
不同機(jī)制下的不同隔離級別
SQL標(biāo)準(zhǔn)定義了四種隔離級別闷供,分別是讀未提交,讀已提交统诺,可重復(fù)讀歪脏,可串行化。很明顯粮呢,越低隔離級別的事務(wù)并發(fā)行更好婿失,但是一致性更低钞艇,嚴(yán)格來說,低隔離級別的事務(wù)是不符合A和I的豪硅,常用的隔離級別多為讀已提交和可重復(fù)度哩照。
但是隔離級別的定義是基于鎖并發(fā)控制實(shí)現(xiàn)的,基于MVCC機(jī)制實(shí)現(xiàn)的數(shù)據(jù)庫事務(wù)表現(xiàn)行為會稍有不同懒浮。
jim gray曾經(jīng)有一篇論文討論不同機(jī)制實(shí)現(xiàn)的數(shù)據(jù)庫隔離級別的不同表現(xiàn)飘弧,并將隔離級別擴(kuò)展到7個。見下圖:
基于此將常見的傳統(tǒng)數(shù)據(jù)庫隔離級別統(tǒng)計如下:
- SYBASE支持的隔離級別:degree 0(read uncommitted)砚著、degree 1(read committed)次伶、degree 2(repeatable read)、degree 3(serializable isolation)赖草;
- ORACLE支持的隔離級別:read committed(consistent read)学少、serializable(snapshot isolation);
- DB2支持的隔離級別:read uncommitted秧骑、cursor stability版确、read stability、repeatable read乎折;
- Postgresql支持的隔離級別:read committed(consistent read)绒疗、repeatable read(snapshot isolation)、serializable isolation(Serialaizable Snapshot Isolation)骂澄;
- SQL Server支持的隔離級別:read uncommitted吓蘑、read committed snapshot 、read committed 坟冲、repeatable read磨镶、snapshot isolation、serializable isolation健提;
- MySQL支持的隔離級別:read uncommitted琳猫、read committed(consistent read)、repeatable read(snapshot isolation)私痹、serializable isolation脐嫂;
幻讀(P3/A3)和寫偏斜(A5B)
上圖的各個字母都是數(shù)據(jù)庫的各種不一致現(xiàn)象。如果把寫操作記作w紊遵,讀操作記作r账千,那么這些有害依賴可以表示為下圖
identifier | query | phenomena |
---|---|---|
P0 | w1[x]...w2[x]...((c1 or a1) and (c2 or a2) in any order) | Dirty Write |
P1 | w1[x]...r2[x]...((c1 or a1) and (c2 or a2) in any order) | Dirty Read |
P2 | r1[x]...w2[x]...((c1 or a1) and (c2 or a2) any order) | Fuzzy / Non-Repeatable Read |
P3 | r1[P]...w2[y in P]...((c1 or a1) and (c2 or a2) any order) | Phantom |
P4 | r1[x]...w2[x]...w1[x]...c1 | Lost Update |
P4C | rc1[x]...w2[x]...w1[x]...c1 | Lost Update |
A3 | r1[P]...w2[y in P]...c2....r1[P]...c1 | Phantom |
A5A | r1[x]...w2[x]...w2[y]...c2...r1[y]...(c1 or a1) | Read Skew |
A5B | r1[x]...r2[y]...w1[y]...w2[x]...(c1 and c2 occur) | Write Skew |
mysql中的可重復(fù)度
幻讀
mysql是支持MVCC機(jī)制實(shí)現(xiàn)的數(shù)據(jù)庫,因此很多人(包括我)會想當(dāng)然認(rèn)為他的SI應(yīng)該就是標(biāo)準(zhǔn)的實(shí)現(xiàn)暗膜,不會出現(xiàn)幻讀(A3/P3)的現(xiàn)象匀奏。接下來,請看如下例子:
如上圖所示桦山,事務(wù)2的insert發(fā)生在兩次select之間攒射,這兩次select也如SI一樣正確的顯示了該看到的結(jié)果醋旦,但是update發(fā)生之后,一切就變了会放,MySQL的RR隔離級別也會幻讀K瞧搿!咧最!
寫偏斜
也許有人會說捂人,mysql同時也是使用鎖的,因此發(fā)生幻讀不奇怪矢沿,所以我們可以看接下來這個寫偏斜的經(jīng)典例子:
顯然滥搭,mysql也是會發(fā)生寫偏斜的。
mysql中可重復(fù)讀的實(shí)現(xiàn)
看源碼可以發(fā)現(xiàn)捣鲸,mysql中的讀操作是使用MVCC機(jī)制實(shí)現(xiàn)瑟匆,可以正確的查找到需要的行,但是寫操作實(shí)現(xiàn)的時候有兩點(diǎn)和我想的不太一樣:
- 寫操作永遠(yuǎn)讀取已提交的數(shù)據(jù)栽惶,并沒有走M(jìn)VCC的邏輯愁溜;
- 寫操作的并發(fā)是通過鎖控制的,不檢查更新行是否是對本事務(wù)可見的外厂。
MVCC機(jī)制行的可見條件很簡單冕象,可以總結(jié)為兩句話:
- 對不同事務(wù),插入事務(wù)已提交汁蝶,刪除事務(wù)未提交(update可以看做先刪除后插入)渐扮;
- 對本事務(wù),插入的statement發(fā)生在自己之前掖棉,刪除的statement未發(fā)生或在自己之后墓律;
套用幻讀那個例子,本來事務(wù)1是不該看到新插入的行的(因?yàn)椴环峡梢姉l件1)幔亥,但是update只讀取最新的行只锻,因此對新插入的行做了一次更新,導(dǎo)致該行符合可見條件2紫谷,再次select就可以查到這個行。
根據(jù)這個實(shí)現(xiàn)捐寥,我們可以推理出笤昨,mysql的可重復(fù)讀同樣會發(fā)生lost update和read skew,只要測試的事務(wù)中存在寫操作握恳。具體例子可見此處
mysql的可重復(fù)讀是比SI更低的隔離級別瞒窒,在發(fā)生幻讀時,SI隔離級別事物的正確行為應(yīng)該是后提交的事務(wù)回滾乡洼,而mysql兩個事務(wù)都可以提交崇裁,顯然匕坯,他的一致性更低,但是并發(fā)性更好(回滾率低)拔稳,這是一次在用戶使用習(xí)慣葛峻,性能和一致性之間的權(quán)衡,至于優(yōu)劣巴比,就見仁見智了术奖,至少現(xiàn)在看來不壞。
postgresql中的可重復(fù)讀
無幻讀
pg實(shí)現(xiàn)的隔離級別是比較標(biāo)準(zhǔn)的轻绞,可重復(fù)度級別(實(shí)際是SI)沒有幻讀采记,這里舉兩個例子
第一個例子
類比mysql的第一個例子,和mysql不同政勃,可以看到pg的事務(wù)update的時候只更新了兩行唧龄,不包括新插入的行
第二個例子
當(dāng)該行同時被兩個可重復(fù)級別的事務(wù)更新時,后提交的事務(wù)會回滾奸远,因?yàn)楦轮荒茉谧钚碌男猩蠄?zhí)行既棺,否則就是丟失更新了。
寫偏斜
可以看到然走,pg的可重復(fù)級別事務(wù)援制,還是存在寫偏斜的,這是符合標(biāo)準(zhǔn)的芍瑞。
參考文檔
- 《A Critique of ANSI SQL Isolation Levels》
- mysql源碼
- pg源碼
- https://github.com/ept/hermitage/blob/master/mysql.md
廣告
最后晨仑,打個廣告,如果對創(chuàng)業(yè)拆檬,分布式數(shù)據(jù)庫和開源社區(qū)感興趣洪己,歡迎加入我們,實(shí)習(xí)和工作都很歡迎竟贯!
pingcap是國內(nèi)為數(shù)不多的newsql方向的分布式數(shù)據(jù)庫答捕,維護(hù)國內(nèi)最頂級的開源社區(qū),關(guān)注度近萬屑那,做類f1+spanner架構(gòu)拱镐,和多家公司有合作關(guān)系。
TiDB: https://github.com/pingcap/tidb
TiKV: https://github.com/pingcap/tikv
Email: xuwentao@pingcap.com
微信: fbisland