數據庫的事務的四大屬性和四大隔離級別(mysql)

一、什麼是事務

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

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

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

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

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

二、四大屬性

分別是原子性、一致性、隔離性、持久性。

1、原子性(Atomicity)
原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,因此事務的操作如果成功就必須要完全應用到數據庫,如果操作失敗則不能對數據庫有任何影響。

2、一致性(Consistency)
一致性是指事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之後都必須處於一致性狀態。舉例來說,假設用戶A和用戶B兩者的錢加起來一共是1000,那麼不管A和B之間如何轉賬、轉幾次賬,事務結束後兩個用戶的錢相加起來應該還得是1000,這就是事務的一致性。

3、隔離性(Isolation)
隔離性是當多個用戶併發訪問數據庫時,比如同時操作同一張表時,數據庫爲每一個用戶開啓的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。關於事務的隔離性數據庫提供了多種隔離級別,稍後會介紹到。

4、持久性(Durability)
持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。例如我們在使用JDBC操作數據庫時,在提交事務方法後,提示用戶事務操作完成,當我們程序執行完成直到看到提示後,就可以認定事務已經正確提交,即使這時候數據庫出現了問題,也必須要將我們的事務完全執行完成。否則的話就會造成我們雖然看到提示事務處理完畢,但是數據庫因爲故障而沒有執行事務的重大錯誤。這是不允許的。

三、四大隔離級別

3.1 什麼是隔離性?

隔離性是指當多個用戶併發操作數據庫時,數據庫爲每一個用戶開啓不同的事務,這些事務之間相互不干擾,相互隔離。

3.2 爲什麼要隔離?

如果事務之間不是互相隔離的會出現:

  1. 更新丟失(Lost update)
  2. 髒讀(dirty read)
  3. 不可重複讀(non-repeatable read)
  4. 幻讀(phantom read)

3.2.1更新丟失(Lost update)

如果多個線程操作,基於同一個查詢結構對錶中的記錄進行修改,那麼後修改的記錄將會覆蓋前面修改的記錄,前面的修改就丟失掉了,這就叫做更新丟失。這是因爲系統沒有執行任何的鎖操作,因此併發事務並沒有被隔離開來。
第1類丟失更新:事務A撤銷時,把已經提交的事務B的更新數據覆蓋了。
在這裏插入圖片描述
第2類丟失更新:事務A覆蓋事務B已經提交的數據,造成事務B所做的操作丟失。

解決方法:對行加鎖,只允許併發一個更新事務。

3.2.2髒讀(Dirty Reads)

髒讀(Dirty Read):A事務讀取B事務尚未提交的數據並在此基礎上操作,而B事務執行回滾,那麼A讀取到的數據就是髒數據。
在這裏插入圖片描述
解決辦法:如果在第一個事務提交前,任何其他事務不可讀取其修改過的值,則可以避免該問題。

3.2.3不可重複讀(Non-repeatable Reads)

一個事務對同一行數據重複讀取兩次,但是卻得到了不同的結果。事務T1讀取某一數據後,事務T2對其做了修改,當事務T1再次讀該數據時得到與前一次不同的值。
在這裏插入圖片描述
解決辦法:如果只有在修改事務完全提交之後纔可以讀取數據,則可以避免該問題。

3.2.4幻讀(幻象讀 )

指兩次執行同一條 select 語句會出現不同的結果,第二次讀會增加一數據行,並沒有說這兩次執行是在同一個事務中。一般情況下,幻象讀應該正是我們所需要的。但有時候卻不是,如果打開的遊標,在對遊標進行操作時,並不希望新增的記錄加到遊標命中的數據集中來。隔離級別爲 遊標穩定性 的,可以阻止幻象讀。例如:目前工資爲1000的員工有10人。那麼事務1中讀取所有工資爲1000的員工,得到了10條記錄;這時事務2向員工表插入了一條員工記錄,工資也爲1000;那麼事務1再次讀取所有工資爲1000的員工共讀取到了11條記錄。
在這裏插入圖片描述
解決辦法:如果在操作事務完成數據處理之前,任何其他事務都不可以添加新數據,則可避免該問題。

正是爲了解決以上情況,數據庫提供了幾種隔離級別。

3.3 事務的隔離級別

數據庫事務的隔離級別有4個,由低到高依次爲Read uncommitted(未授權讀取、讀未提交)、Read committed(授權讀取、讀提交)、Repeatable read(可重複讀取)、Serializable(序列化),這四個級別可以逐個解決髒讀、不可重複讀、幻象讀這幾類問題。

3.3.1 Read uncommitted(未授權讀取、讀未提交):

如果一個事務已經開始寫數據,則另外一個事務則不允許同時進行寫操作,但允許其他事務讀此行數據。該隔離級別可以通過“排他寫鎖”實現。這樣就避免了更新丟失,卻可能出現髒讀。也就是說事務B讀取到了事務A未提交的數據。
Read committed(授權讀取、讀提交):
讀取數據的事務允許其他事務繼續訪問該行數據,但是未提交的寫事務將會禁止其他事務訪問該行。該隔離級別避免了髒讀,但是卻可能出現不可重複讀。事務A事先讀取了數據,事務B緊接了更新了數據,並提交了事務,而事務A再次讀取該數據時,數據已經發生了改變。

3.3.2 Repeatable read(可重複讀取)mysql默認:

可重複讀是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那麼,在第一個事務中的兩次讀數據之間,即使第二個事務對數據進行修改,第一個事務兩次讀到的的數據是一樣的。這樣就發生了在一個事務內兩次讀到的數據是一樣的,因此稱爲是可重複讀。讀取數據的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。這樣避免了不可重複讀取和髒讀,但是有時可能出現幻象讀。(讀取數據的事務)這可以通過“共享讀鎖”和“排他寫鎖”實現。

3.3.3 Serializable(序列化):

提供嚴格的事務隔離。它要求事務序列化執行,事務只能一個接着一個地執行,但不能併發執行。如果僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的數據不會被剛執行查詢操作的事務訪問到。序列化是最高的事務隔離級別,同時代價也花費最高,性能很低,一般很少使用,在該級別下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻像讀。
在這裏插入圖片描述
隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大。對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設爲Read Committed。它能夠避免髒讀取,而且具有較好的併發性能。儘管它會導致不可重複讀、幻讀和第二類丟失更新這些併發問題,在可能出現這類問題的個別場合,可以由應用程序採用悲觀鎖或樂觀鎖來控制。大多數數據庫的默認級別就是Read committed,比如Sql Server , Oracle。MySQL的默認隔離級別就是Repeatable read

3.4 總結

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

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

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

這一次,帶你搞清楚MySQL的事務隔離級別!
mysql的事務四個特性以及事務的四個隔離級別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章