久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

MySQL的事務隔離級別介紹

142次閱讀
沒有評論

共計 4177 個字符,預計需要花費 11 分鐘才能閱讀完成。

本篇內容介紹了“MySQL 的事務隔離級別介紹”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

什么是事務?

數據庫事務(簡稱:事務)是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作序列構成。—— 維基百科

事務的概念看上去不難,但是需要注意以下幾個點:

1、首先,事務就是要保證一組數據庫操作,要么全部成功,要么全部失敗;

2、在 MySQL 中,事務支持是在引擎層實現的;

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

今天,我們的主角是隔離性,隔離性是指當多個用戶并發操作數據庫時,數據庫為每一個用戶開啟不同的事務,這些事務之間相互不干擾,相互隔離。

為什么需要隔離性?

如果事務之間不是互相隔離的,可能將會出現以下問題。

1、臟讀

臟讀(dirty read),簡單來說,就是一個事務在處理過程中讀取了另外一個事務未提交的數據。

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

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

舉例

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

①給丸趣 TV 小編賬號加一分錢,這時丸趣 TV 小編看到了,覺得很欣慰;
②你的賬號減一分錢;

2、不可重復讀

不可重復讀(non-repeatable read),是指一個事務范圍內,多次查詢某個數據,卻得到不同的結果。

在第一個事務中的兩次讀取數據之間,由于第二個事務的修改,第一個事務兩次讀到的數據可能就是不一樣的。

舉例

接著上一個例子,假設你真給丸趣 TV 小編打賞了一分錢,丸趣 TV 小編樂得屁顛屁顛地去準備提現,一查,發現真多了一分錢。

在這同時,在我還沒有提現成功之前,丸趣 TV 小編的老婆已經提前將這一分錢支走了,丸趣 TV 小編此時再次查賬,發現一分錢也沒了。

臟讀和不可重復讀有點懵逼?

二者的區別是,臟讀是某一事務讀取了另外一個事務未提交的數據,不可重復讀是讀取了其他事務提交的數據。

其實,有些情況下,不可重復讀不是問題,比如,丸趣 TV 小編提現期間,一分錢被老婆支走了,這不是問題!

而臟讀,是可以通過設置隔離級別避免的。

3、幻讀

幻讀(phantom read),是事務非獨立執行時發生的一種現象。

例如事務 T1 對一個表中所有的行的某個數據項做了從“1”修改為“2”的操作,這時事務 T2 又對這個表中插入了一行數據項為“1”的數據,并且提交給數據庫。

而操作事務 T1 的用戶如果再查看剛剛修改的數據,會發現數據怎么還是 1?其實這行是從事務 T2 中添加的,就好像產生幻覺一樣,這就是發生了幻讀。

舉例

其實上面的解釋已經是一個例子了,但是還是要舉個例子。

比如,丸趣 TV 小編準備提取你打賞的一分錢,提取完了,這時又有其他熱心網友打賞了一分錢,丸趣 TV 小編一看,明明已經取出了,怎么又有一分錢!?

丸趣 TV 小編此時以為像做夢一樣,我覺得也可以叫「夢讀」,哈哈。

幻讀和不可重復讀都是讀取了另一條已經提交的事務(這點就臟讀不同),所不同的是不可重復讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。

事務的隔離級別

為了解決上面可能出現的問題,我們就需要設置隔離級別,也就是事務之間按照什么規則進行隔離,將事務隔離到什么程度。

首先,需要明白一點,隔離程度越強,事務的執行效率越低。

ANSI/ISO SQL 定義了 4 種標準隔離級別:

① Serializable(串行化):花費最高代價但最可靠的事務隔離級別。

“寫”會加“寫鎖”,“讀”會加“讀鎖”。當出現讀寫鎖沖突的時候,后訪問的事務必須等前一個事務執行完成,才能繼續執行。

事務 100% 隔離,可避免臟讀、不可重復讀、幻讀的發生。

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

但如果這個事務在讀取某個范圍內的記錄時,其他事務又在該范圍內插入了新的記錄,當之前的事務再次讀取該范圍的記錄時,會產生幻行,這就是幻讀。

可避免臟讀、不可重復讀的發生。但是可能會出現幻讀。

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

可避免臟讀的發生,但是可能會造成不可重復讀。

大多數數據庫的默認級別就是 Read committed,比如 Sql Server , Oracle。

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

任何情況都無法保證。

隔離級別

下圖中是一個很好的例子,分別解釋了四種事務隔離級別下,事務 B 能夠讀取到的結果。

看著還是有點懵逼?那我們再舉個例子。

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

隔離級別是串行化,則在事務 B 執行「將 1 改成 2」的時候,會被鎖住。直到事務 A 提交后,事務 B 才可以繼續執行。

再次總結

讀未提交:別人改數據的事務尚未提交,我在我的事務中也能讀到。
讀已提交:別人改數據的事務已經提交,我在我的事務中才能讀到。
可重復讀:別人改數據的事務已經提交,我在我的事務中也不去讀。
串行:我的事務尚未提交,別人就別想改數據。

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

總的來說,事務隔離級別越高,越能保證數據的完整性和一致性,但是付出的代價卻是并發執行效率的低下。

隔離級別的實現

事務的機制是通過視圖(read-view)來實現的并發版本控制(MVCC),不同的事務隔離級別創建讀視圖的時間點不同。

可重復讀是每個事務重建讀視圖,整個事務存在期間都用這個視圖。

讀已提交是每條 SQL 創建讀視圖,在每個 SQL 語句開始執行的時候創建的。隔離作用域僅限該條 SQL 語句。

讀未提交是不創建,直接返回記錄上的最新值

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

這里的視圖可以理解為數據副本,每次創建視圖時,將當前已持久化的數據創建副本,后續直接從副本讀取,從而達到數據隔離效果。

隔離級別的實現

我們每一次的修改操作,并不是直接對行數據進行操作。

比如我們設置 id 為 3 的行的 A 屬性為 10,并不是直接修改表中的數據,而是新加一行。

同時數據表其實還有一些隱藏的屬性,比如每一行的事務 id,所以每一行數據可能會有多個版本,每一個修改過它的事務都會有一行,并且還會有關聯的 undo 日志,表示這個操作原來的數據是什么,可以用它做回滾。

那么為什么要這么做?

因為如果我們直接把數據修改了,那么其他事務就用不了原先的值了,違反了事務的一致性。

那么一個事務讀取某一行的數據到底返回什么結果呢?

取決于隔離級別,如果是 Read Committed,那么返回的是最新的事務的提交值,所以未提交的事務修改的值是不會讀到的,這就是 Read Committed 實現的原理。

如果是 Read Repeatable 級別,那么只能返回發起時間比當前事務早的事務的提交值,和比當前事務晚的刪除事務刪除的值。這其實就是 MVCC 方式。

undo log

undo log 中存儲的是老版本數據。假設修改表中 id=2 的行數據,把 Name= B 修改為 Name = B2,那么 undo 日志就會用來存放 Name= B 的記錄,如果這個修改出現異常,可以使用 undo 日志來實現回滾操作,保證事務的一致性。

當一個舊的事務需要讀取數據時,為了能讀取到老版本的數據,需要順著 undo 鏈找到滿足其可見性的記錄。當版本鏈很長時,通常可以認為這是個比較耗時的操作。

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

當前值是 4,但是在查詢這條記錄的時候,不同時刻啟動的事務會有不同的 read-view。

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

同時你會發現,即使現在有另外一個事務正在將 4 改成 5,這個事務跟 read-view A、B、C 對應的事務是不會沖突的。

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

insert undo log : 事務對 insert 新記錄時產生的 undolog,只在事務回滾時需要,并且在事務提交后就可以立即丟棄。(誰會對剛插入的數據有可見性需求呢!!)

update undo log : 事務對記錄進行 delete 和 update 操作時產生的 undo log。不僅在事務回滾時需要,一致性讀也需要,所以不能隨便刪除,只有當數據庫所使用的快照中不涉及該日志記錄,對應的回滾日志才會被 purge 線程刪除。

何時刪除?

在不需要的時候才刪除。也就是說,系統會判斷,當沒有事務再需要用到這些回滾日志時,回滾日志會被刪除。

就是當系統里沒有比這個回滾日志更早的 read-view 的時候。

長事務

直觀感覺,一個事務花費很長時間不能夠結束,就是一個長的事務,簡稱長事務(Long Transaction)。

長事務是數據庫用戶經常會碰到且是非常令人頭疼的問題。長事務處理需要恰當進行,如處理不當可能引起數據庫的崩潰,為用戶帶來不必要的損失。

根據上面的論述,長事務意味著系統里面會存在很老的事務視圖。

由于這些事務隨時可能訪問數據庫里面的任何數據,所以這個事務提交之前,數據庫里面它可能用到的 undo log 都必須保留,這就會導致大量占用存儲空間。

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

除了對回滾段的影響,長事務還占用鎖資源,也可能拖垮整個庫,這個我們會在后面講鎖的時候展開。

因此,我們要盡量避免長事務。

“MySQL 的事務隔離級別介紹”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注丸趣 TV 網站,丸趣 TV 小編將為大家輸出更多高質量的實用文章!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-28發表,共計4177字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 梨树县| 临西县| 岢岚县| 弥渡县| 航空| 崇信县| 乳山市| 苍南县| 犍为县| 榕江县| 玉树县| 遵义市| 西和县| 泌阳县| 东台市| 施秉县| 岳西县| 民县| 华容县| 屏山县| 永登县| 库车县| 从江县| 大埔县| 巧家县| 惠州市| 渝中区| 时尚| 古蔺县| 苏尼特左旗| 台南县| 乌拉特后旗| 舞钢市| 会同县| 汉沽区| 保山市| 余姚市| 邯郸市| 佛坪县| 云南省| 永康市|