詳解MySQL事務(wù)的四大特性和隔離級別
1、事務(wù)的四大特性(ACID)
1.1、原子性(Atomicity) 原子性是指事務(wù)包含的一系列操作要么全部成功,要么全部回滾,不存在部分成功或者部分回滾,是一個(gè)不可分割的操作整體。
1.2、一致性(Consistency)
一致性是可以理解為事務(wù)對數(shù)據(jù)完整性約束的遵循,這些約束可能包括主鍵約束、唯一索引約束、外鍵約束等等。事務(wù)執(zhí)行前后,數(shù)據(jù)都是合法的狀態(tài),不會(huì)違背任何的數(shù)據(jù)完整性
就拿轉(zhuǎn)賬來說,A和B加起來有5000塊錢,不管A和B如何轉(zhuǎn)賬,轉(zhuǎn)幾次賬,A和B加起來的錢永遠(yuǎn)都是5000塊。
總之,可以理解為:一致性是為了保證數(shù)據(jù)的完整性。
1.3、隔離性(Isolation)
隔離性是指當(dāng)多個(gè)用戶并發(fā)操作數(shù)據(jù)庫,比如操作同一張表,數(shù)據(jù)庫為每一個(gè)用戶開啟的事務(wù),不能被其他的事務(wù)所干擾或者影響,事務(wù)之間是彼此獨(dú)立的。
1.4、永久性(Durability)
永久性是指一個(gè)事務(wù)一旦提交了,那么對數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久的,即使是在數(shù)據(jù)庫發(fā)生故障時(shí),也不會(huì)丟失事務(wù)提交的數(shù)據(jù)。
2、事務(wù)的隔離性
事務(wù)的隔離性。當(dāng)多個(gè)線程開啟事務(wù)操作數(shù)據(jù)庫中的數(shù)據(jù)時(shí),數(shù)據(jù)庫要能進(jìn)行隔離操作,以保證各個(gè)線程獲取數(shù)據(jù)的準(zhǔn)確性; 如果不考慮事務(wù)的隔離性,會(huì)發(fā)生以下幾個(gè)問題;
2.1、臟讀
臟讀是指一個(gè)事務(wù)在處理過程中讀取了另一個(gè)事務(wù)未提交的數(shù)據(jù)。比如,A向B轉(zhuǎn)賬
- update account set money = money + 100 where name = 'B';
- update account set money = money - 100 where name = 'A'
當(dāng)只執(zhí)行第一條SQL時(shí),A通知B查看賬戶,B發(fā)現(xiàn)確實(shí)錢已到賬(此時(shí)即發(fā)生了臟讀),
而之后無論第二條SQL是否執(zhí)行,只要該事務(wù)不提交,則所有操作都將回滾,那么當(dāng)B以后再次查看賬戶時(shí)就會(huì)發(fā)現(xiàn)錢其實(shí)并沒有轉(zhuǎn)
2.2、不可重復(fù)讀
不可重復(fù)讀是指在對于數(shù)據(jù)庫中的某個(gè)數(shù)據(jù),一個(gè)事務(wù)范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值,這是由于在查詢間隔,被另一個(gè)事務(wù)修改并提交了。例如事務(wù)T1在讀取某一數(shù)據(jù),而事務(wù)T2立馬修改了這個(gè)數(shù)據(jù)并且提交事務(wù)給數(shù)據(jù)庫,事務(wù)T1再次讀取該數(shù)據(jù)就得到了不同的結(jié)果,發(fā)生了不可重復(fù)讀。不可重復(fù)讀和臟讀的區(qū)別是,臟讀是某一事務(wù)讀取了另一個(gè)事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了前一事務(wù)提交的數(shù)據(jù)。在某些情況下,不可重復(fù)讀并不是問題,比如我們多次查詢某個(gè)數(shù)據(jù)當(dāng)然以最后查詢得到的結(jié)果為主。但在另一些情況下就有可能發(fā)生問題,例如對于同一個(gè)數(shù)據(jù)A和B依次查詢就可能不同,A和B就可能打起來了……
2.3、幻讀
幻讀是事務(wù)非獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象。
例如事務(wù)T1對一個(gè)表中所有的行的某個(gè)數(shù)據(jù)項(xiàng)做了從“1”修改為“2”的操作,這時(shí)事務(wù)T2又對這個(gè)表中插入了一行數(shù)據(jù)項(xiàng),而這個(gè)數(shù)據(jù)項(xiàng)的數(shù)值還是為“1”并且提交給數(shù)據(jù)庫。而操作事務(wù)T1的用戶如果再查看剛剛修改的數(shù)據(jù),會(huì)發(fā)現(xiàn)還有一行沒有修改,其實(shí)這行是從事務(wù)T2中添加的,就好像產(chǎn)生幻覺一樣,這就是發(fā)生了幻讀。
幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù)(這點(diǎn)就臟讀不同),所不同的是不可重復(fù)讀查詢的都是同一個(gè)數(shù)據(jù)項(xiàng),而幻讀針對的是一批數(shù)據(jù)整體(比如數(shù)據(jù)的個(gè)數(shù))
3、MySQL的隔離級別
Serializable (串行化):可避免臟讀、不可重復(fù)讀、幻讀的發(fā)生 > * Repeatable read (可重復(fù)讀):可避免臟讀、不可重復(fù)讀的發(fā)生 > * Read committed (讀已提交):可避免臟讀的發(fā)生 > * Read uncommitted (讀未提交):最低級別,任何情況都無法保證
以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,當(dāng)然級別越高,執(zhí)行效率就越低。
像Serializable這樣的級別,就是以鎖表的方式(類似于Java多線程中的鎖)使得其他的線程只能在鎖外等待)
所以平時(shí)選用何種隔離級別應(yīng)該根據(jù)實(shí)際情況。
3.1、MySQL和Oracle隔離級別的對比
MySQL支持以上4種隔離級別,默認(rèn)的隔離級別是Repeatable read (可重復(fù)讀)
Oracle只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,默認(rèn)的隔離級別是Read committed (讀已提交)
查看mysql事務(wù)的隔離級別
- select @@tx_isolation
4、舉例說明事務(wù)的隔離級別
4.1、Repeatable read (可重復(fù)讀)
開啟兩個(gè)事務(wù)A、B,分別對同一個(gè)表中的數(shù)據(jù)進(jìn)行操作,操作流程如下:
結(jié)果:在Repeatable read的隔離級別下,T4得到的結(jié)果仍然是Tom:
此時(shí),如果將事務(wù)A提交之后,再查詢,得到的將是最新的結(jié)果:
4.2、Read committed (讀已提交)
現(xiàn)在看看將隔離級別設(shè)置為讀已提交,返回的結(jié)果又是什么
- set session transaction isolation level read committed
注意:此種修改只對當(dāng)前會(huì)話有效,如果要全局修改隔離級別,需要到mysql安裝目錄下的my.ini最后添加
- transaction-isolation = REPEATABLE-READ
結(jié)果:在Read committed的隔離級別下,T4得到的結(jié)果就是最新,說明讀到了已提交的: