一、什么是事務?
簡單說就是邏輯上的一組操作,要么都執行,要么都不執行。
舉個例子,假如小明要給小紅轉賬100元,這個轉賬會涉及到兩個關鍵操作:①將小明的余額減少100元。? ②將小紅的余額增加100元 。但是萬一再這兩個操作之間突然出現錯誤,比如說銀行系統崩潰,導致小明余額減少而小紅的余額沒有增加,這樣就不對了。事務就是保證這兩個關鍵操作要么都成功,要么都失敗。
二、事務的特性ACID
?1、原子性:事務是最小的執行單位,不允許分割。事務的原子性確保動作要么全部完成,要么全不起作用。
2、一致性:執行事務前后,數據保持一致。例如轉賬業務中,無論事務是否成功,轉賬者和收款人的總額應該是不變的。
3、隔離性:并發訪問數據庫時,一個用戶的事務不被其他事務所干擾,各并發事務之間的數據是獨立的。
4、持久性:一個事務被提交之后,他對數據庫的改變是持久的,即使數據庫發生故障也不應該對其有任何影響。
實現:
持久性:通過 redo log來保證的
原子性:通過 undo log來保證的
隔離性:通過 MVCC 或鎖機制來保證的
一致性:通過持久性+原子性+隔離性來保證
三、并發事務帶來的問題
在典型的應用程序中,多個事務并發運行,經常會操作相同的數據來完成各自的任務(多個用戶對統一數據進行操作)。并發雖然是必須的,但是可能會導致以下的問題。
- 臟讀(Dirty Read):當一個事務正在訪問數據并且對數據進行了修改,此時還未提交到數據庫中,這時另一個事務也訪問并使用了這個數據,由于上個事務還未提交,此時他讀到的就是“臟數據”,根據“臟數據”所做的操作可能時不正確的。
- 丟失修改(Lost of Modify):指一個事務讀取到一個數據,另一個事務也訪問了該數據。那么在第一個事務修改了這個數據后,第二個事務也進行了修改,此時第一個事務的修改結果就被覆蓋了,也就是丟失了,因此稱為丟失修改。? ?例如:事務1讀取某表中的數據A=20,事務2也讀取A=20,事務1修改A=A-1,事務2也修改A=A-1,最終結果A=19,事務1的修改被丟失。
- 死鎖(Deadlock):兩個或多個事務相互等待對方釋放資源,導致系統無法繼續執行。這種情況下,只能通過終止其中一個事務或者回滾來解決死鎖。
- 不可重復讀(Unrepeatableread):一個事務在讀取某個數據后,另一個事務修改了該數據并提交。當第一個事務再次讀取同一數據時,得到的結果與之前不一致。因此稱為不可重復讀。
- 幻讀(Phantom read):幻讀與不可重復讀類似,它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現一些原本不存在的記錄,就好像發生了幻覺一樣,所以稱為幻讀。
不可重復度和幻讀的區別:
不可重復讀的重點是修改,幻讀的重點在于新增或者刪除。
例1(同樣的條件, 你讀取過的數據, 再次讀取出來發現值不一樣了 ):事務1中的A先生讀取自己的工資為 1000的操作還沒完成,事務2中的B先生就修改了A的工資為2000,導 致A再讀自己的工資時工資變為 2000;這就是不可重復讀。
例2(同樣的條件, 第1次和第2次讀出來的記錄數不一樣 ):假某工資單表中工資大于3000的有4人,事務1讀取了所有工資大于3000的人,共查到4條記錄,這時事務2 又插入了一條工資大于3000的記錄,事務1再次讀取時查到的記錄就變為了5條,這樣就導致了幻讀。
四、事務隔離級別
SQL 標準定義了四個隔離級別:
-
READ-UNCOMMITTED(讀取未提交): 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀。
-
READ-COMMITTED(讀取已提交): 允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生。
-
REPEATABLE-READ(可重復讀): 對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生。
-
SERIALIZABLE(可串行化): 最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。
隔離級別 | 臟讀 | 不可重復讀 | 幻影讀 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
?