一流昏、事務(wù)
事務(wù)是由一組SQL語句組成的邏輯處理單元但两,是滿足 ACID 特性的一組操作鬓梅,可以通過 Commit 提交一個(gè)事務(wù),也可以使用 Rollback 進(jìn)行回滾谨湘。事務(wù)具有以下4個(gè)屬性绽快,通常簡稱為事務(wù)的ACID屬性:
- 原子性(Atomicity):事務(wù)是一個(gè)原子操作單元,其對數(shù)據(jù)的修改紧阔,要么全都執(zhí)行坊罢,要么全都不執(zhí)行。比如在同一個(gè)事務(wù)中的SQL語句擅耽,要么全部執(zhí)行成功活孩,要么全部執(zhí)行失敗」猿穑回滾可以用日志來實(shí)現(xiàn)诱鞠,日志記錄著事務(wù)所執(zhí)行的修改操作挎挖,在回滾時(shí)反向執(zhí)行這些修改操作即可。
- 一致性(Consistent):在事務(wù)開始和完成時(shí)航夺,數(shù)據(jù)都必須保持一致狀態(tài)蕉朵。這意味著所有相關(guān)的數(shù)據(jù)規(guī)則都必須應(yīng)用于事務(wù)的修改,以保持?jǐn)?shù)據(jù)的完整性阳掐;事務(wù)結(jié)束時(shí)始衅,所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如B樹索引或雙向鏈表)也都必須是正確的。 以轉(zhuǎn)賬為例子缭保,A向B轉(zhuǎn)賬汛闸,假設(shè)轉(zhuǎn)賬之前這兩個(gè)用戶的錢加起來總共是2000,那么A向B轉(zhuǎn)賬之后艺骂,不管這兩個(gè)賬戶怎么轉(zhuǎn)诸老,A用戶的錢和B用戶的錢加起來的總額還是2000,這個(gè)就是事務(wù)的一致性钳恕。
- 隔離性(Isolation):數(shù)據(jù)庫系統(tǒng)提供一定的隔離機(jī)制别伏,保證事務(wù)在不受外部并發(fā)操作影響的“獨(dú)立”環(huán)境執(zhí)行。 隔離性是當(dāng)多個(gè)用戶并發(fā)訪問數(shù)據(jù)庫時(shí)忧额,比如操作同一張表時(shí)厘肮,數(shù)據(jù)庫為每一個(gè)用戶開啟的事務(wù),不能被其他事務(wù)的操作所干擾睦番,多個(gè)并發(fā)事務(wù)之間要相互隔離类茂。即要達(dá)到這么一種效果:對于任意兩個(gè)并發(fā)的事務(wù) T1 和 T2,在事務(wù) T1 看來托嚣,T2 要么在 T1 開始之前就已經(jīng)結(jié)束巩检,要么在 T1 結(jié)束之后才開始,這樣每個(gè)事務(wù)都感覺不到有其他事務(wù)在并發(fā)地執(zhí)行示启。
- 持久性(Durable):事務(wù)完成之后碴巾,它對于數(shù)據(jù)的修改是永久性的,即使出現(xiàn)系統(tǒng)故障也能夠保持丑搔。 可以通過數(shù)據(jù)庫備份和恢復(fù)來實(shí)現(xiàn)厦瓢,在系統(tǒng)發(fā)生奔潰時(shí),使用備份的數(shù)據(jù)庫進(jìn)行數(shù)據(jù)恢復(fù)啤月。
MySQL 默認(rèn)采用自動提交模式煮仇。也就是說,如果不顯式使用 START TRANSACTION 語句來開始一個(gè)事務(wù)谎仲,那么每個(gè)查詢都會被當(dāng)做一個(gè)事務(wù)自動提交浙垫。
這幾個(gè)特性不是一種平級關(guān)系:
- 只有滿足一致性,事務(wù)的執(zhí)行結(jié)果才是正確的。
- 在無并發(fā)的情況下夹姥,事務(wù)串行執(zhí)行杉武,隔離性一定能夠滿足。此時(shí)要只要能滿足原子性辙售,就一定能滿足一致性轻抱。
- 在并發(fā)的情況下,多個(gè)事務(wù)并發(fā)執(zhí)行旦部,事務(wù)不僅要滿足原子性祈搜,還需要滿足隔離性,才能滿足一致性士八。
- 事務(wù)滿足持久化是為了能應(yīng)對數(shù)據(jù)庫奔潰的情況容燕。
二、并發(fā)一致性問題
Ⅰ婚度、更新丟失(Lost Update)
T1 和 T2 兩個(gè)事務(wù)都對一個(gè)數(shù)據(jù)進(jìn)行修改蘸秘,T1 先修改,T2 隨后修改蝗茁,T2 的修改覆蓋了 T1 的修改醋虏。
例如,兩個(gè)程序員修改同一java文件评甜。每程序員獨(dú)立地更改其副本,然后保存更改后的副本仔涩,這樣就覆蓋了原始文檔忍坷。最后保存其更改副本的編輯人員覆蓋前一個(gè)程序員所做的更改。
如果在一個(gè)程序員完成并提交事務(wù)之前熔脂,另一個(gè)程序員不能訪問同一文件佩研,則可避免此問題。
Ⅱ霞揉、臟讀
一句話:事務(wù)B讀取到了事務(wù)A已修改但尚未提交的的數(shù)據(jù)旬薯,還在這個(gè)數(shù)據(jù)基礎(chǔ)上做了操作。此時(shí)适秩,如果A事務(wù)回滾Rollback绊序,B讀取的數(shù)據(jù)無效,不符合一致性要求秽荞。
解決辦法: 把數(shù)據(jù)庫的事務(wù)隔離級別調(diào)整到 READ_COMMITTED
T1 修改一個(gè)數(shù)據(jù)骤公,T2 隨后讀取這個(gè)數(shù)據(jù)。如果 T1 撤銷了這次修改扬跋,那么 T2 讀取的數(shù)據(jù)是臟數(shù)據(jù)阶捆。
Ⅲ、不可重復(fù)讀(Non-Repeatable Reads)
在一個(gè)事務(wù)內(nèi),多次讀同一個(gè)數(shù)據(jù)洒试。在這個(gè)事務(wù)還沒有結(jié)束時(shí)倍奢,另一個(gè)事務(wù)也訪問該同一數(shù)據(jù)。那么垒棋,在第一個(gè)事務(wù)的兩次讀數(shù)據(jù)之間卒煞。由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)讀到的數(shù)據(jù)可能不一樣捕犬,這樣就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的跷坝,因此稱為不可重復(fù)讀,即原始讀取不可重復(fù)碉碉。
一句話:一個(gè)事務(wù)范圍內(nèi)兩個(gè)相同的查詢卻返回了不同數(shù)據(jù)柴钻。
同時(shí)操作,事務(wù)1分別讀取事務(wù)2操作時(shí)和提交后的數(shù)據(jù)垢粮,讀取的記錄內(nèi)容不一致贴届。不可重復(fù)讀是指在同一個(gè)事務(wù)內(nèi),兩個(gè)相同的查詢返回了不同的結(jié)果蜡吧。
解決辦法: 如果只有在修改事務(wù)完全提交之后才可以讀取數(shù)據(jù)毫蚓,則可以避免該問題。把數(shù)據(jù)庫的事務(wù)隔離級別調(diào)整到REPEATABLE_READ
T2 讀取一個(gè)數(shù)據(jù)昔善,T1 對該數(shù)據(jù)做了修改元潘。如果 T2 再次讀取這個(gè)數(shù)據(jù),此時(shí)讀取的結(jié)果和第一次讀取的結(jié)果不同君仆。
Ⅳ翩概、幻讀
一個(gè)事務(wù)T1按相同的查詢條件重新讀取以前檢索過的數(shù)據(jù),卻發(fā)現(xiàn)其他事務(wù)T2插入了滿足其查詢條件的新數(shù)據(jù)返咱,這種現(xiàn)象就稱為“幻讀”钥庇。(和可重復(fù)讀類似,但是事務(wù) T2 的數(shù)據(jù)操作僅僅是插入和刪除咖摹,不是修改數(shù)據(jù)评姨,讀取的記錄數(shù)量前后不一致)
一句話:事務(wù)A 讀取到了事務(wù)B提交的新增數(shù)據(jù),不符合隔離性萤晴。
解決辦法: 如果在操作事務(wù)完成數(shù)據(jù)處理之前吐句,任何其他事務(wù)都不可以添加新數(shù)據(jù),則可避免該問題店读。把數(shù)據(jù)庫的事務(wù)隔離級別調(diào)整到 SERIALIZABLE_READ蕴侧。
T1 讀取某個(gè)范圍的數(shù)據(jù),T2 在這個(gè)范圍內(nèi)插入新的數(shù)據(jù)两入,T1 再次讀取這個(gè)范圍的數(shù)據(jù)净宵,此時(shí)讀取的結(jié)果和和第一次讀取的結(jié)果不同。
三、事務(wù)隔離級別
"臟讀"择葡、"不可重復(fù)讀"和"幻讀"紧武,其實(shí)都是數(shù)據(jù)庫讀一致性問題,必須由數(shù)據(jù)庫提供一定的事務(wù)隔離機(jī)制來解決敏储。
數(shù)據(jù)庫的事務(wù)隔離越嚴(yán)格阻星,并發(fā)副作用越小,但付出的代價(jià)也就越大已添,因?yàn)槭聞?wù)隔離實(shí)質(zhì)上就是使事務(wù)在一定程度上 “串行化”進(jìn)行妥箕,這顯然與“并發(fā)”是矛盾的。同時(shí)更舞,不同的應(yīng)用對讀一致性和事務(wù)隔離程度的要求也是不同的畦幢,比如許多應(yīng)用對“不可重復(fù)讀”和“幻讀”并不敏感,可能更關(guān)心數(shù)據(jù)并發(fā)訪問的能力缆蝉。
MYSQL秤畲校看當(dāng)前數(shù)據(jù)庫的事務(wù)隔離級別:show variables like 'tx_isolation'
;
Ⅰ、讀未提交 (Read Uncommitted)
最低的隔離等級刊头,允許其他事務(wù)看到?jīng)]有提交的數(shù)據(jù)黍瞧,會導(dǎo)致臟讀。
Ⅱ原杂、讀已提交 (Read Committed)
被讀取的數(shù)據(jù)可以被其他事務(wù)修改印颤,這樣可能導(dǎo)致不可重復(fù)讀。也就是說穿肄,事務(wù)讀取的時(shí)候獲取讀鎖年局,但是在讀完之后立即釋放(不需要等事務(wù)結(jié)束),而寫鎖則是事務(wù)提交之后才釋放被碗,釋放讀鎖之后某宪,就可能被其他事務(wù)修改數(shù)據(jù)仿村。該等級也是 SQL Server 默認(rèn)的隔離等級锐朴。
Ⅲ、可重復(fù)讀(Repeatable Read)
所有被 Select 獲取的數(shù)據(jù)都不能被修改蔼囊,這樣就可以避免一個(gè)事務(wù)前后讀取數(shù)據(jù)不一致的情況焚志。但是卻沒有辦法控制幻讀,因?yàn)檫@個(gè)時(shí)候其他事務(wù)不能更改所選的數(shù)據(jù)畏鼓,但是可以增加數(shù)據(jù)酱酬,即前一個(gè)事務(wù)有讀鎖但是沒有范圍鎖,為什么叫做可重復(fù)讀等級呢云矫?那是因?yàn)樵摰燃壗鉀Q了下面的不可重復(fù)讀問題膳沽。(引申:現(xiàn)在主流數(shù)據(jù)庫都使用 MVCC 并發(fā)控制,使用之后RR(可重復(fù)讀)隔離級別下是不會出現(xiàn)幻讀的現(xiàn)象。)
MYSQL默認(rèn)是REPEATABLE-READ
挑社。
Ⅳ陨界、串行化(Serializable)
所有事務(wù)一個(gè)接著一個(gè)的執(zhí)行,這樣可以避免幻讀 (phantom read)痛阻,對于基于鎖來實(shí)現(xiàn)并發(fā)控制的數(shù)據(jù)庫來說菌瘪,串行化要求在執(zhí)行范圍查詢的時(shí)候,需要獲取范圍鎖阱当,如果不是基于鎖實(shí)現(xiàn)并發(fā)控制的數(shù)據(jù)庫俏扩,則檢查到有違反串行操作的事務(wù)時(shí),需回滾該事務(wù)弊添。
Ⅴ录淡、總結(jié)
- 讀未提交: 一個(gè)事務(wù)還沒提交時(shí),它做的變更就能被別的事務(wù)看到表箭。
- 讀提交: 一個(gè)事務(wù)提交之后赁咙,它做的變更才會被其他事務(wù)看到。
- 可重復(fù)讀 : 一個(gè)事務(wù)執(zhí)行過程中看到的數(shù)據(jù)免钻,總是跟這個(gè)事務(wù)在啟動時(shí)看到的數(shù)據(jù)是一致的彼水。當(dāng)然在可重復(fù)讀隔離級別下,未提交變更對其他事務(wù)也是不可見的极舔。
- 串行化: 顧名思義是對于同一行記錄凤覆,“寫”會加“寫鎖”,“讀”會加“讀鎖”拆魏。當(dāng)出現(xiàn)讀寫鎖沖突的時(shí)候盯桦,后訪問的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成,才能繼續(xù)執(zhí)行渤刃。
四個(gè)級別逐漸增強(qiáng)拥峦,每個(gè)級別解決一個(gè)問題,事務(wù)級別越高卖子,性能越差略号,大多數(shù)環(huán)境(Read committed 就可以用了)
隔離級別 | 讀數(shù)據(jù)一致性 | 臟讀 | 不可重復(fù)讀 | 幻影讀 |
---|---|---|---|---|
未提交讀 | 最低級別 | √ | √ | √ |
提交讀 | 語句級 | × | √ | √ |
可重復(fù)讀 | 事務(wù)級 | × | × | √ |
可串行讀 | 最高級別,事務(wù)級 | × | × | × |
寫在最后
- 第一:看完點(diǎn)贊,感謝您對作者的認(rèn)可洋闽;
- ...
- 第二:隨手轉(zhuǎn)發(fā)玄柠,分享知識,讓更多人學(xué)習(xí)到诫舅;
- ...
- 第三:記得點(diǎn)關(guān)注羽利,每天更新的!?浮这弧!
- ...