總結(jié)
- 四種隔離級別:
讀未提交(read uncommitted)RU:數(shù)據(jù)會讀取其他事務(wù)未更新到數(shù)據(jù)的數(shù)據(jù)阁危∪焖觯可能會存在臟讀、不可重復(fù)讀识啦、幻讀的問題。
讀已提交(read committed)RC:數(shù)據(jù)只能讀取其他事務(wù)提交的數(shù)據(jù)神妹,不存在臟讀颓哮,但是可能會存在不可重復(fù)讀、幻讀的問題鸵荠。
可重復(fù)讀(repeatable read)RR:事務(wù)執(zhí)行過程中看到的數(shù)據(jù)冕茅,總是和這個事務(wù)開啟時看到的數(shù)據(jù)是一致的。在可重復(fù)讀的隔離級別下,未提交的事務(wù)對其他事務(wù)也是不可見的姨伤。不存在臟讀哨坪、不可重復(fù)讀,但是可能會存在幻讀問題姜挺。
串行化(serializable)S:存在讀寫鎖沖突時齿税,后訪問的事務(wù)會等前一個事務(wù)執(zhí)行完畢后,再繼續(xù)執(zhí)行炊豪。- MySQL采用了MVVC(多版本并發(fā)控制)解決讀已提交凌箕、可重復(fù)讀隔離問題。
執(zhí)行一條SQL語句词渤,都會保存兩個隱藏的列牵舱。一個是保存創(chuàng)建版本,一個保存過期版本缺虐,儲存的系統(tǒng)版本號芜壁。
每次開啟一個事務(wù)都會系統(tǒng)會遞增一個系統(tǒng)版本號,作為事務(wù)的版本號。
select高氮,查詢早于當前事務(wù)的數(shù)據(jù)慧妄。
insert,添加版本號剪芍。
delete塞淹,為刪除的行把版本號作為刪除標識。
update罪裹,先插入一條數(shù)據(jù)饱普,保存當前系統(tǒng)版本號,同時保存原來的行作為行刪除標志状共。
前言
一個事務(wù)具有ACID特性套耕,也就是(Atomicity、Consistency峡继、Isolation冯袍、Durability,即原子性碾牌、一致性颠猴、隔離性、持久性)小染,本文主要講解一下其中的Isolation翘瓮,也就是事務(wù)的隔離性。
隔離性
四種級別
-
讀未提交(read uncommitted)RU
一個事務(wù)還沒提交時裤翩,它修改的數(shù)據(jù)都可以被別的事物看到资盅。 -
讀已提交(read committed)RC
一個事務(wù)提交之后调榄,它修改的數(shù)據(jù)才會被別的事物看到。 -
可重復(fù)讀(repeatable read)RR
一個事務(wù)執(zhí)行過程中看到的數(shù)據(jù)呵扛,總是和這個事務(wù)開啟時看到的數(shù)據(jù)是一致的每庆。在可重復(fù)讀的隔離級別下,未提交的事務(wù)對其他事務(wù)也是不可見的今穿。 -
串行化(serializable)S
數(shù)據(jù)的讀和寫都會加鎖缤灵,讀會加讀鎖,寫會加寫鎖蓝晒。當遇到讀寫鎖沖突時腮出,后訪問的事務(wù)必須等前一個事務(wù)執(zhí)行完成后,再繼續(xù)執(zhí)行芝薇。
以上四種隔離級別胚嘲,由上往下隔離強度越來越大,但是執(zhí)行效率會隨之降低洛二。在設(shè)置隔離級別時候馋劈,需要在隔離級別和執(zhí)行效率兩者做平衡取舍。
eg:
在不同隔離級別下晾嘶,事務(wù)A會有哪些不同的返回結(jié)果妓雾,也就是圖中的V1、V2垒迂、V3的返回值分別是什么械姻。
- 如果隔離級別是讀未提交,事務(wù)B修改后數(shù)據(jù)無需提交事務(wù)娇斑,就能被事務(wù)A讀取策添,所以V1材部、V2毫缆、V3的值都是2。
- 如果隔離級別是讀已提交乐导,事務(wù)B修改后需要提交后苦丁,修改后的數(shù)據(jù)才能被事務(wù)A讀取,所以V1的值是1物臂,事務(wù)B提交旺拉,事務(wù)A讀取修改后的數(shù)據(jù),所以V2的值是2,V3的值也是2。
- 如果隔離級別是可重復(fù)讀棵磷,整個事務(wù)看到的事務(wù)和事務(wù)開啟時看到的數(shù)據(jù)是一致的蛾狗,開啟看到的數(shù)據(jù)是1,所以V1仪媒、V2的值都是1,事務(wù)A提交之后沉桌,獲取到修改后的數(shù)據(jù),所以V3的值是2。
- 如果隔離級別是串行化留凭,會被鎖住佃扼,此時事務(wù)B對應(yīng)的線程處于阻塞狀態(tài),直到事務(wù)A提交之后蔼夜,事務(wù)B才會繼續(xù)將1改成2兼耀。所以V1、V2的值是1求冷,V3的值是2瘤运。
MySQL默認的隔離級別是可重復(fù)讀。
數(shù)據(jù)不一致現(xiàn)象
三種現(xiàn)象
- 臟讀
事務(wù)A修改數(shù)據(jù)遵倦,事務(wù)B讀取了數(shù)據(jù)后事務(wù)A報錯回滾尽超,修改的數(shù)據(jù)沒有提交到數(shù)據(jù)庫中,此時事務(wù)B讀取修改的數(shù)據(jù)就是一個臟讀梧躺,也就是一個事務(wù)讀取到另一個事務(wù)未提交的數(shù)據(jù)就是臟讀似谁。 - 不可重復(fù)讀
事務(wù)A在同一個事務(wù)上多次讀取同一個數(shù)據(jù),在事務(wù)A還沒有結(jié)束時掠哥,事務(wù)B修改了該數(shù)據(jù)巩踏,由于事務(wù)B的修改,導(dǎo)致事務(wù)A兩次讀取的數(shù)據(jù)不一致续搀,就出現(xiàn)了不可以重復(fù)讀的現(xiàn)象塞琼。 - 幻讀
事務(wù)A根據(jù)條件查詢得到N條數(shù)據(jù),但此時事務(wù)B更改或者增加了M條符合事務(wù)A查詢的條件的數(shù)據(jù)禁舷。這樣當事務(wù)A再次查詢的時候發(fā)現(xiàn)會有N + M條數(shù)據(jù)彪杉,產(chǎn)生了幻讀。
四種隔離級別對應(yīng)可以解決什么不一致現(xiàn)象:
- 讀未提交(read uncommitted)
數(shù)據(jù)會讀取其他事務(wù)未更新到數(shù)據(jù)的數(shù)據(jù)牵咙∨山可能會存在臟讀、不可重復(fù)讀洁桌、幻讀的問題渴丸。 - 讀已提交(read committed)
數(shù)據(jù)只能讀取其他事務(wù)提交的數(shù)據(jù),不存在臟讀另凌,但是可能會存在不可重復(fù)讀谱轨、幻讀的問題。 - 可重復(fù)讀(repeatable read)
事務(wù)執(zhí)行過程中看到的數(shù)據(jù)吠谢,總是和這個事務(wù)開啟時看到的數(shù)據(jù)是一致的土童。在可重復(fù)讀的隔離級別下,未提交的事務(wù)對其他事務(wù)也是不可見的工坊。不存在臟讀献汗、不可重復(fù)讀错沃,但是可能會存在幻讀問題。 - 串行化(serializable)
存在讀寫鎖沖突時雀瓢,后訪問的事務(wù)會等前一個事務(wù)執(zhí)行完畢后枢析,再繼續(xù)執(zhí)行。
隔離級別原理
隔離級別的主要是多版本并發(fā)控制MVCC,MVCC是通過保存數(shù)據(jù)在某個時間點的快照來實現(xiàn)的刃麸。
InnoDB實現(xiàn)的MVCC醒叁,是通過在每行記錄后面保存兩個隱藏列來實現(xiàn),一個是保存行的創(chuàng)建時間泊业,另一個是保存行的過期時間把沼。當然存儲的不是時間,而是系統(tǒng)版本號吁伺。每開啟一個新的事務(wù)饮睬,系統(tǒng)版本號先自動遞增,該系統(tǒng)版本號會作為事務(wù)的版本號篮奄,用來和查詢到的每行記錄的版本號做比較捆愁。
比如在可重復(fù)讀隔離級別下,MVCC是如何操作的:
SELECT
InnoDB會根據(jù)以下兩個條件檢查每行記錄:
只有符合上述兩個條件的記錄窟却,才能返回作為查詢的結(jié)果昼丑。
InnoDB只查找版本號早于當前事務(wù)的數(shù)據(jù)行(系統(tǒng)版本號小于或者等于事務(wù)的系統(tǒng)版本號),這樣可以確保事務(wù)讀取的行夸赫,要么是在事務(wù)開始前就存在菩帝,要么是事務(wù)自身插入或者更新過。
行的刪除版本要么未定義茬腿,要么大于當前事務(wù)版本號呼奢。這可以確保事務(wù)讀取到的行,在事務(wù)開始之前未被刪除切平。
INSERT
InnoDB為新插入的每一行保存當前系統(tǒng)版本號作為行版本號握础。
DELETE
InnoDB為刪除的每一行保存當前系統(tǒng)版本號作為行刪除的標識。
UPDATE
InnoDB為插入一行新記錄揭绑,保存當前系統(tǒng)版本號作為行版本號弓候,同時保存當前系統(tǒng)版本號到原來的行作為行刪除標識郎哭。
保存著兩個額外的系統(tǒng)版本號他匪,大多數(shù)讀操作都可以不用加鎖。這樣設(shè)計是的讀數(shù)據(jù)的操作很簡單夸研,性能很好邦蜜,并且也能保證只會讀取到符合標準的行。不足之處是每行記錄都需要額外的存儲空間亥至,需要做更多的行檢查工作悼沈,以及一些額外的維護工作贱迟。
MVCC只在讀已提交和可重復(fù)讀兩個隔離級別下生效。其他兩個隔離級別下MVCC都不能生效絮供,因為讀未提交總是讀取到最新的數(shù)據(jù)行衣吠,無需記錄當前事務(wù)版本號。而串行化會對所有的讀寫都會進行加鎖壤靶,先讀缚俏、先寫的先執(zhí)行,后讀贮乳、后寫的后執(zhí)行忧换。也不需要記錄記錄版本號精心比對。
InnoDB的行數(shù)據(jù)有多個版本向拆,每個數(shù)據(jù)版本都有自己的row trx_id亚茬,每個事務(wù)或者語句都有自己的一致性視圖。查詢語句是一致性讀浓恳,一致性讀會根據(jù)row trx_id和一致性視圖確定數(shù)據(jù)版本的可見性刹缝。
可重復(fù)讀,只查詢事務(wù)啟動前所有事務(wù)提交完成的數(shù)據(jù)颈将。
讀已提交赞草,只查詢語句啟動前(一個事務(wù)內(nèi)可以執(zhí)行多個語句)所有事務(wù)提交完成的數(shù)據(jù)。