【MySQL】搞懂ACID原則和事務隔離級別

宜未雨而綢繆,毋臨渴而掘井mysql

說說MySQL的事務

數據庫事務(Database Transaction) ,是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。sql

一個數據庫事務一般包含對數據庫進行讀或寫的一個操做序列。它的存在包含有如下兩個目的:數據庫

  • 爲數據庫提供一個從失敗恢復正常狀態的方法,同時提供了數據庫即便在異常狀態下仍然能保持一致性的方法。
  • 當多個應用程序併發訪問數據庫時,能夠在這些應用程序之間提供一個隔離的方法,以防止彼此的操做相互干擾。

固然並非全部的數據庫都支持事務,事務通常有四個屬性:原子性、一致性、隔離性、持久性。簡稱:ACID原則。接下來咱們舉例逐個分析:併發

  • 原子性:顧名思義原子就不可在分的,事務做爲一個總體,對數據庫的執行要麼成功,要麼失敗。
  • 一致性:事務從一個一致狀態轉換到另外一個一致狀態。
  • 隔離性:多個事務併發執行,事務之間的執行互不干擾。
  • 持久性:一旦一個事務提交,它對數據庫的操做將永久保存到數據庫當中。

舉例:分佈式

咱們用一個轉帳的案例結合每一個性質分析,例如:帳戶A向帳戶B轉帳,主要分爲一下幾個步驟:性能

  1. 從A帳號中把餘額讀出來(500)。
  2. 對A帳號作減法操做(500-100)。
  3. 把結果寫回A帳號中(400)。
  4. 從B帳號中把餘額讀出來(500)。
  5. 對B帳號作加法操做(500+100)。
  6. 把結果寫回B帳號中(600)。

原子性排序

保證6個步驟要麼所有執行,要麼所有不執行,若是失敗了就把事務回滾到轉帳的初始狀態。好比:在執行到第五步的以後,帳戶B忽然註銷了找不到了,此時帳戶A的錢也扣了,就必須事務回滾到原來各自的狀態也就是A的餘額500。事務

一致性get

在轉帳以前A和B的帳戶共有500+500=1000,而轉帳成功以後,A和B的帳戶是400+600=1000,就是數據的狀態在執行該事務操做以後從一個狀態改變到了另一個狀態it

隔離性

在A給B轉帳過程當中,只要事務沒有提交,A和B的帳戶餘額不會存在變化。可是此時帳戶C也在向帳戶B轉帳,最終兩個事務提交以後帳戶B的餘額應該是帳戶A轉帳的金額加上帳戶C轉帳的金額。也就是說多個事務之間不會相互影響,至於C給B轉帳的時候獲取B的餘額是已經加了A給B轉帳的餘額仍是沒加,這個和事務的隔離級別有關係。

持久性

一旦轉帳成功(事務提交),兩個帳戶的裏面的錢就會真的發生變化(會把數據寫入數據庫作持久化保存)!

事務的隔離級別

  • Read-uncommitted(讀未提交):最低級別,以上狀況均沒法保證。
  • Read-committed(讀已提交):可避免髒讀狀況發生
  • Repeatable-read(可重複讀,默認):可避免髒讀、不可重複讀狀況的發生不能夠避免虛讀
  • Serializable:可避免髒讀、不可重複讀、虛讀狀況的發生。(串行,不只有read、write鎖還有range lock範圍鎖(沒有where鎖全表,有where鎖where範圍);對一張表的全部增刪改操做必須順序執行,性能最差)
隔離級別 髒讀 不可重複讀 幻讀
Read-uncommitted
Read-committed ×
Repeatable-read × ×
Serializable × × ×

隔離級別詳解

  • Read uncommitted

做用:全部事務均可以看到其餘未提交事務的執行結果

例子:

又到月底了,小明的老婆要準備給小明發生活費了,小明的老婆給小明打了500塊,但該事務並無提交,而此時小明正好在查餘額,發現是550塊,高興的差點蹦了起來.天有不測風雲,忽然小明的老婆發現多打了50塊,因而回滾事務,修改金額,而後將事務提交,最後小明空歡喜異常。

  • Read committed

做用:一個事務只能看見已經提交事務所作的改變

例子:

某個夜黑風高的夜晚,小明豐富的夜生活開始了,小明拿着工資卡去消費,pos機讀取卡的信息的時候有500,而此時小紅也正好在網上轉帳,把小明工資卡的500元轉到另外一帳戶,並小明以前提交了事務,當小明釦款時,系統檢查到小明的工資卡已經沒有錢,扣款失敗,小明十分納悶,明明卡里有錢,爲何會說餘額不足,出現上述狀況,即咱們所說的不可重複讀,兩個併發的事務,「事務1:小明消費」、「事務2:小紅網上轉帳」,事務1事先讀取了數據,事務2緊接了更新了數據,並提交了事務,而事務1再次讀取該數據時,數據已經發生了改變,當隔離級別設置爲Read committed時,避免了髒讀,可是可能會形成不可重複讀

  • Repeatable read

    • 備註
      1. MySQL的默認隔離級別
      2. 從原理上看,可重複讀是靠MVCC(多版本併發控制)保證的,該模式下,保證事務只能讀取到當前事務開啓以前已經提交的事務的修改以及當前事務自己對數據的修改
    • 區別
      1. 不可重複讀的重點是修改,好比屢次讀取一條記錄發現其中某些列的值被修改(但mysql因爲MVCC機制並不會有),
      2. 幻讀的重點在於新增或者刪除,好比屢次範圍讀取發現記錄增多或減小了。

做用:當用戶讀取某一範圍的數據行時,另外一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,發現和以前不同。

例子:

小紅最近發現小明老是很晚回家而且常常不接電話,因而小紅開始查小明當月信用卡的總消費金額,消費金額爲50,而小明此時正好在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄,並提交了事務,隨後小紅將小明當月信用卡消費的明細打印了出來,卻發現消費總額爲1050元,小紅很詫異,覺得出現了幻覺

  • Serializable(串行)

做用:最高級別,防止上述3種狀況,事務串行執行,慎用這是最高的隔離級別,它經過強制事務排序,使之不可能相互衝突,從而避免了髒讀,不可重複讀,幻讀。簡言之,它是在每一個讀的數據行上加上共享鎖。在這個級別,可能致使大量的超時現象和鎖競爭,併發性能最差,在分佈式事務中可能會被用到。

參考文獻:
http://www.hollischuang.com/archives/898

相關文章
相關標籤/搜索