MySQL的事務(wù)隔離級(jí)別介紹

本篇內(nèi)容介紹了“MySQL的事務(wù)隔離級(jí)別介紹”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

道外網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。成都創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)。

什么是事務(wù)?

數(shù)據(jù)庫(kù)事務(wù)(簡(jiǎn)稱:事務(wù))是數(shù)據(jù)庫(kù)管理系統(tǒng)執(zhí)行過程中的一個(gè)邏輯單位,由一個(gè)有限的數(shù)據(jù)庫(kù)操作序列構(gòu)成?!?維基百科

事務(wù)的概念看上去不難,但是需要注意以下幾個(gè)點(diǎn):

1、首先,事務(wù)就是要保證一組數(shù)據(jù)庫(kù)操作,要么全部成功,要么全部失??;

2、在 MySQL 中,事務(wù)支持是在引擎層實(shí)現(xiàn)的;

3、并不是所有引擎都支持事務(wù),如 MyISAM 就不支持,InnoDB 就支持;


今天,我們的主角是隔離性,隔離性是指當(dāng)多個(gè)用戶并發(fā)操作數(shù)據(jù)庫(kù)時(shí),數(shù)據(jù)庫(kù)為每一個(gè)用戶開啟不同的事務(wù),這些事務(wù)之間相互不干擾,相互隔離。

為什么需要隔離性?

如果事務(wù)之間不是互相隔離的,可能將會(huì)出現(xiàn)以下問題。

1、臟讀

臟讀(dirty read),簡(jiǎn)單來說,就是一個(gè)事務(wù)在處理過程中讀取了另外一個(gè)事務(wù)未提交的數(shù)據(jù)。

這種未提交的數(shù)據(jù)我們稱之為臟數(shù)據(jù)。依據(jù)臟數(shù)據(jù)所做的操作肯能是不正確的。

還記得上節(jié)中我們提到的 dirty page 嗎?這種臨時(shí)處理的未提交的,都是「臟」的。

舉例

MySQL的事務(wù)隔離級(jí)別介紹

但是,若該事務(wù)未提交成功,最終所有操作都會(huì)回滾,小編看到的一分錢也只是鏡花水月。比如,你給小編贊賞 1 分錢,整個(gè)事務(wù)需要兩個(gè)步驟:

①給小編賬號(hào)加一分錢,這時(shí)小編看到了,覺得很欣慰;
②你的賬號(hào)減一分錢;

MySQL的事務(wù)隔離級(jí)別介紹

2、不可重復(fù)讀

不可重復(fù)讀(non-repeatable read),是指一個(gè)事務(wù)范圍內(nèi),多次查詢某個(gè)數(shù)據(jù),卻得到不同的結(jié)果。

在第一個(gè)事務(wù)中的兩次讀取數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,第一個(gè)事務(wù)兩次讀到的數(shù)據(jù)可能就是不一樣的。

舉例

MySQL的事務(wù)隔離級(jí)別介紹

接著上一個(gè)例子,假設(shè)你真給小編打賞了一分錢,小編樂得屁顛屁顛地去準(zhǔn)備提現(xiàn),一查,發(fā)現(xiàn)真多了一分錢。

在這同時(shí),在我還沒有提現(xiàn)成功之前,小編的老婆已經(jīng)提前將這一分錢支走了,小編此時(shí)再次查賬,發(fā)現(xiàn)一分錢也沒了。

MySQL的事務(wù)隔離級(jí)別介紹

臟讀和不可重復(fù)讀有點(diǎn)懵逼?

二者的區(qū)別是,臟讀是某一事務(wù)讀取了另外一個(gè)事務(wù)未提交的數(shù)據(jù),不可重復(fù)讀是讀取了其他事務(wù)提交的數(shù)據(jù)。

其實(shí),有些情況下,不可重復(fù)讀不是問題,比如,小編提現(xiàn)期間,一分錢被老婆支走了,這不是問題!

而臟讀,是可以通過設(shè)置隔離級(jí)別避免的。

3、幻讀

幻讀(phantom read),是事務(wù)非獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象。

例如事務(wù) T1 對(duì)一個(gè)表中所有的行的某個(gè)數(shù)據(jù)項(xiàng)做了從“1”修改為“2”的操作,這時(shí)事務(wù) T2 又對(duì)這個(gè)表中插入了一行數(shù)據(jù)項(xiàng)為“1”的數(shù)據(jù),并且提交給數(shù)據(jù)庫(kù)。

而操作事務(wù) T1 的用戶如果再查看剛剛修改的數(shù)據(jù),會(huì)發(fā)現(xiàn)數(shù)據(jù)怎么還是 1?其實(shí)這行是從事務(wù) T2 中添加的,就好像產(chǎn)生幻覺一樣,這就是發(fā)生了幻讀。

舉例

MySQL的事務(wù)隔離級(jí)別介紹

其實(shí)上面的解釋已經(jīng)是一個(gè)例子了,但是還是要舉個(gè)例子。

比如,小編準(zhǔn)備提取你打賞的一分錢,提取完了,這時(shí)又有其他熱心網(wǎng)友打賞了一分錢,小編一看,明明已經(jīng)取出了,怎么又有一分錢???

小編此時(shí)以為像做夢(mèng)一樣,我覺得也可以叫「夢(mèng)讀」,哈哈。

幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù)(這點(diǎn)就臟讀不同),所不同的是不可重復(fù)讀查詢的都是同一個(gè)數(shù)據(jù)項(xiàng),而幻讀針對(duì)的是一批數(shù)據(jù)整體(比如數(shù)據(jù)的個(gè)數(shù))。

事務(wù)的隔離級(jí)別

為了解決上面可能出現(xiàn)的問題,我們就需要設(shè)置隔離級(jí)別,也就是事務(wù)之間按照什么規(guī)則進(jìn)行隔離,將事務(wù)隔離到什么程度。

首先,需要明白一點(diǎn),隔離程度越強(qiáng),事務(wù)的執(zhí)行效率越低。

ANSI/ISO SQL 定義了 4 種標(biāo)準(zhǔn)隔離級(jí)別:

① Serializable(串行化):花費(fèi)最高代價(jià)但最可靠的事務(wù)隔離級(jí)別。

“寫”會(huì)加“寫鎖”,“讀”會(huì)加“讀鎖”。當(dāng)出現(xiàn)讀寫鎖沖突的時(shí)候,后訪問的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成,才能繼續(xù)執(zhí)行。

事務(wù) 100% 隔離,可避免臟讀、不可重復(fù)讀、幻讀的發(fā)生。

② Repeatable read(可重復(fù)讀,默認(rèn)級(jí)別):多次讀取同一范圍的數(shù)據(jù)會(huì)返回第一次查詢的快照,即使其他事務(wù)對(duì)該數(shù)據(jù)做了更新修改。事務(wù)在執(zhí)行期間看到的數(shù)據(jù)前后必須是一致的。

但如果這個(gè)事務(wù)在讀取某個(gè)范圍內(nèi)的記錄時(shí),其他事務(wù)又在該范圍內(nèi)插入了新的記錄,當(dāng)之前的事務(wù)再次讀取該范圍的記錄時(shí),會(huì)產(chǎn)生幻行,這就是幻讀。

可避免臟讀、不可重復(fù)讀的發(fā)生。但是可能會(huì)出現(xiàn)幻讀。

③ Read committed (讀已提交):保證一個(gè)事物提交后才能被另外一個(gè)事務(wù)讀取。另外一個(gè)事務(wù)不能讀取該事物未提交的數(shù)據(jù)。

可避免臟讀的發(fā)生,但是可能會(huì)造成不可重復(fù)讀。

大多數(shù)數(shù)據(jù)庫(kù)的默認(rèn)級(jí)別就是 Read committed,比如 Sql Server , Oracle。

④ Read uncommitted (讀未提交):最低的事務(wù)隔離級(jí)別,一個(gè)事務(wù)還沒提交時(shí),它做的變更就能被別的事務(wù)看到。

任何情況都無法保證。

MySQL的事務(wù)隔離級(jí)別介紹隔離級(jí)別

下圖中是一個(gè)很好的例子,分別解釋了四種事務(wù)隔離級(jí)別下,事務(wù) B 能夠讀取到的結(jié)果。

MySQL的事務(wù)隔離級(jí)別介紹

看著還是有點(diǎn)懵逼?那我們?cè)倥e個(gè)例子。

A,B 兩個(gè)事務(wù),分別做了一些操作,操作過程中,在不同隔離級(jí)別下查看變量的值:

MySQL的事務(wù)隔離級(jí)別介紹

隔離級(jí)別是串行化,則在事務(wù) B 執(zhí)行「將 1 改成 2」的時(shí)候,會(huì)被鎖住。直到事務(wù) A 提交后,事務(wù) B 才可以繼續(xù)執(zhí)行。

再次總結(jié)

讀未提交:別人改數(shù)據(jù)的事務(wù)尚未提交,我在我的事務(wù)中也能讀到。
讀已提交:別人改數(shù)據(jù)的事務(wù)已經(jīng)提交,我在我的事務(wù)中才能讀到。
可重復(fù)讀:別人改數(shù)據(jù)的事務(wù)已經(jīng)提交,我在我的事務(wù)中也不去讀。
串行:我的事務(wù)尚未提交,別人就別想改數(shù)據(jù)。

這 4 種隔離級(jí)別,并行性能依次降低,安全性依次提高。

總的來說,事務(wù)隔離級(jí)別越高,越能保證數(shù)據(jù)的完整性和一致性,但是付出的代價(jià)卻是并發(fā)執(zhí)行效率的低下。


隔離級(jí)別的實(shí)現(xiàn)

事務(wù)的機(jī)制是通過視圖(read-view)來實(shí)現(xiàn)的并發(fā)版本控制(MVCC),不同的事務(wù)隔離級(jí)別創(chuàng)建讀視圖的時(shí)間點(diǎn)不同。

  • 可重復(fù)讀是每個(gè)事務(wù)重建讀視圖,整個(gè)事務(wù)存在期間都用這個(gè)視圖。

  • 讀已提交是每條 SQL 創(chuàng)建讀視圖,在每個(gè) SQL 語(yǔ)句開始執(zhí)行的時(shí)候創(chuàng)建的。隔離作用域僅限該條 SQL 語(yǔ)句。

  • 讀未提交是不創(chuàng)建,直接返回記錄上的最新值

  • 串行化隔離級(jí)別下直接用加鎖的方式來避免并行訪問。

這里的視圖可以理解為數(shù)據(jù)副本,每次創(chuàng)建視圖時(shí),將當(dāng)前已持久化的數(shù)據(jù)創(chuàng)建副本,后續(xù)直接從副本讀取,從而達(dá)到數(shù)據(jù)隔離效果。

隔離級(jí)別的實(shí)現(xiàn)

我們每一次的修改操作,并不是直接對(duì)行數(shù)據(jù)進(jìn)行操作。

比如我們?cè)O(shè)置 id 為 3 的行的 A 屬性為 10,并不是直接修改表中的數(shù)據(jù),而是新加一行。

同時(shí)數(shù)據(jù)表其實(shí)還有一些隱藏的屬性,比如每一行的事務(wù) id,所以每一行數(shù)據(jù)可能會(huì)有多個(gè)版本,每一個(gè)修改過它的事務(wù)都會(huì)有一行,并且還會(huì)有關(guān)聯(lián)的 undo 日志,表示這個(gè)操作原來的數(shù)據(jù)是什么,可以用它做回滾。

那么為什么要這么做?

因?yàn)槿绻覀冎苯影褦?shù)據(jù)修改了,那么其他事務(wù)就用不了原先的值了,違反了事務(wù)的一致性。

那么一個(gè)事務(wù)讀取某一行的數(shù)據(jù)到底返回什么結(jié)果呢?

取決于隔離級(jí)別,如果是 Read Committed,那么返回的是最新的事務(wù)的提交值,所以未提交的事務(wù)修改的值是不會(huì)讀到的,這就是 Read Committed 實(shí)現(xiàn)的原理。

如果是 Read Repeatable 級(jí)別,那么只能返回發(fā)起時(shí)間比當(dāng)前事務(wù)早的事務(wù)的提交值,和比當(dāng)前事務(wù)晚的刪除事務(wù)刪除的值。這其實(shí)就是 MVCC 方式。

undo log

undo log 中存儲(chǔ)的是老版本數(shù)據(jù)。假設(shè)修改表中 id=2 的行數(shù)據(jù),把 Name='B' 修改為 Name = 'B2' ,那么 undo 日志就會(huì)用來存放 Name='B' 的記錄,如果這個(gè)修改出現(xiàn)異常,可以使用 undo 日志來實(shí)現(xiàn)回滾操作,保證事務(wù)的一致性。

當(dāng)一個(gè)舊的事務(wù)需要讀取數(shù)據(jù)時(shí),為了能讀取到老版本的數(shù)據(jù),需要順著 undo 鏈找到滿足其可見性的記錄。當(dāng)版本鏈很長(zhǎng)時(shí),通常可以認(rèn)為這是個(gè)比較耗時(shí)的操作。

假設(shè)一個(gè)值從 1 被按順序改成了 2、3、4,在回滾日志里面就會(huì)有類似下面的記錄。

MySQL的事務(wù)隔離級(jí)別介紹

當(dāng)前值是 4,但是在查詢這條記錄的時(shí)候,不同時(shí)刻啟動(dòng)的事務(wù)會(huì)有不同的 read-view。

如圖中看到的,在視圖 A、B、C 里面,這一個(gè)記錄的值分別是 1、2、4,同一條記錄在系統(tǒng)中可以存在多個(gè)版本,就是數(shù)據(jù)庫(kù)的多版本并發(fā)控制(MVCC)。對(duì)于 read-view A,要得到 1,就必須將當(dāng)前值依次執(zhí)行圖中所有的回滾操作得到。

同時(shí)你會(huì)發(fā)現(xiàn),即使現(xiàn)在有另外一個(gè)事務(wù)正在將 4 改成 5,這個(gè)事務(wù)跟 read-view A、B、C 對(duì)應(yīng)的事務(wù)是不會(huì)沖突的。


另外,在回滾段中的 undo log 分為: insert undo log 和 update undo log:

  • insert undo log : 事務(wù)對(duì) insert 新記錄時(shí)產(chǎn)生的 undolog,只在事務(wù)回滾時(shí)需要,并且在事務(wù)提交后就可以立即丟棄。(誰(shuí)會(huì)對(duì)剛插入的數(shù)據(jù)有可見性需求呢!?。?/p>

  • update undo log : 事務(wù)對(duì)記錄進(jìn)行 delete 和 update 操作時(shí)產(chǎn)生的 undo log。不僅在事務(wù)回滾時(shí)需要,一致性讀也需要,所以不能隨便刪除,只有當(dāng)數(shù)據(jù)庫(kù)所使用的快照中不涉及該日志記錄,對(duì)應(yīng)的回滾日志才會(huì)被 purge 線程刪除。

何時(shí)刪除?

在不需要的時(shí)候才刪除。也就是說,系統(tǒng)會(huì)判斷,當(dāng)沒有事務(wù)再需要用到這些回滾日志時(shí),回滾日志會(huì)被刪除。

就是當(dāng)系統(tǒng)里沒有比這個(gè)回滾日志更早的 read-view 的時(shí)候。

長(zhǎng)事務(wù)

直觀感覺,一個(gè)事務(wù)花費(fèi)很長(zhǎng)時(shí)間不能夠結(jié)束,就是一個(gè)長(zhǎng)的事務(wù),簡(jiǎn)稱長(zhǎng)事務(wù)(Long Transaction)。

長(zhǎng)事務(wù)是數(shù)據(jù)庫(kù)用戶經(jīng)常會(huì)碰到且是非常令人頭疼的問題。長(zhǎng)事務(wù)處理需要恰當(dāng)進(jìn)行,如處理不當(dāng)可能引起數(shù)據(jù)庫(kù)的崩潰,為用戶帶來不必要的損失。

根據(jù)上面的論述,長(zhǎng)事務(wù)意味著系統(tǒng)里面會(huì)存在很老的事務(wù)視圖。

由于這些事務(wù)隨時(shí)可能訪問數(shù)據(jù)庫(kù)里面的任何數(shù)據(jù),所以這個(gè)事務(wù)提交之前,數(shù)據(jù)庫(kù)里面它可能用到的 undo log 都必須保留,這就會(huì)導(dǎo)致大量占用存儲(chǔ)空間。

在 MySQL 5.5 及以前的版本,回滾日志是跟數(shù)據(jù)字典一起放在 ibdata 文件里的,即使長(zhǎng)事務(wù)最終提交,回滾段被清理,文件也不會(huì)變小。

除了對(duì)回滾段的影響,長(zhǎng)事務(wù)還占用鎖資源,也可能拖垮整個(gè)庫(kù),這個(gè)我們會(huì)在后面講鎖的時(shí)候展開。

因此,我們要盡量避免長(zhǎng)事務(wù)。

“MySQL的事務(wù)隔離級(jí)別介紹”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

分享標(biāo)題:MySQL的事務(wù)隔離級(jí)別介紹
標(biāo)題來源:http://muchs.cn/article10/picggo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、建站公司、網(wǎng)站維護(hù)、網(wǎng)站排名、軟件開發(fā)網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)