宜未雨而綢繆,毋臨渴而掘井 說說MySQL的事務 資料庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。 一個資料庫事務通常包含對資料庫進行讀或寫的一個操作序列。它的存在包含有以下兩個目的: 為資料庫提供一個從失敗恢復正 ...
宜未雨而綢繆,毋臨渴而掘井
說說MySQL的事務
資料庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。
一個資料庫事務通常包含對資料庫進行讀或寫的一個操作序列。它的存在包含有以下兩個目的:
- 為資料庫提供一個從失敗恢復正常狀態的方法,同時提供了資料庫即使在異常狀態下仍然能保持一致性的方法。
- 當多個應用程式併發訪問資料庫時,可以在這些應用程式之間提供一個隔離的方法,以防止彼此的操作相互干擾。
當然並不是所有的資料庫都支持事務,事務一般有四個屬性:原子性、一致性、隔離性、持久性。簡稱:ACID原則。接下來我們舉例逐個分析:
- 原子性:顧名思義原子就不可在分的,事務作為一個整體,對資料庫的執行要麼成功,要麼失敗。
- 一致性:事務從一個一致狀態轉換到另一個一致狀態。
- 隔離性:多個事務併發執行,事務之間的執行互不幹擾。
- 持久性:一旦一個事務提交,它對資料庫的操作將永久保存到資料庫當中。
舉例:
我們用一個轉賬的案例結合每個性質分析,例如:賬戶A向賬戶B轉賬,主要分為一下幾個步驟:
- 從A賬號中把餘額讀出來(500)。
- 對A賬號做減法操作(500-100)。
- 把結果寫回A賬號中(400)。
- 從B賬號中把餘額讀出來(500)。
- 對B賬號做加法操作(500+100)。
- 把結果寫回B賬號中(600)。
原子性
保證6個步驟要麼全部執行,要麼全部不執行,如果失敗了就把事務回滾到轉賬的初始狀態。比如:在執行到第五步的之後,賬戶B突然註銷了找不到了,此時賬戶A的錢也扣了,就必須事務回滾到原來各自的狀態也就是A的餘額500。
一致性
在轉賬之前A和B的賬戶共有500+500=1000,而轉賬成功之後,A和B的賬戶是400+600=1000,就是數據的狀態在執行該事務操作之後從一個狀態改變到了另外一個狀態
隔離性
在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
- 備註
- MySQL的預設隔離級別
- 從原理上看,可重覆讀是靠MVCC(多版本併發控制)保證的,該模式下,保證事務只能讀取到當前事務開啟之前已經提交的事務的修改以及當前事務本身對數據的修改
- 區別
- 不可重覆讀的重點是修改,比如多次讀取一條記錄發現其中某些列的值被修改(但mysql由於MVCC機制並不會有),
- 幻讀的重點在於新增或者刪除,比如多次範圍讀取發現記錄增多或減少了。
- 備註
作用:當用戶讀取某一範圍的數據行時,另一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,發現和之前不一樣。
例子:
小紅最近發現小明總是很晚回家並且經常不接電話,於是小紅開始查小明當月信用卡的總消費金額,消費金額為50,而小明此時正好在收銀台買單,消費1000元,即新增了一條1000元的消費記錄,並提交了事務,隨後小紅將小明當月信用卡消費的明細列印了出來,卻發現消費總額為1050元,小紅很詫異,以為出現了幻覺
- Serializable(串列)
作用:最高級別,防止上述3種情況,事務串列執行,慎用這是最高的隔離級別,它通過強制事務排序,使之不可能相互衝突,從而避免了臟讀,可重覆讀,幻讀。簡言之,它是在每個讀的數據行上加上共用鎖。在這個級別,可能導致大量的超時現象和鎖競爭,併發性能最差,在分散式事務中可能會被用到。