1. 什麼是事物
事務(Transaction)是由一系列對系統中數據進行訪問與更新的操作所組成的一個程序執行邏輯單元
。換句話說:一個Session中所進行所有的操作,要麼同時成功,要麼同時失敗。
2. 事物的4個基本特徵ACID
事務具有4個基本特徵,分別是:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔離性(Isolation)
- 持久性(Duration)
2.1 原子性(Atomicity)
事務的原子性是指事務必須是一個原子的操作序列單元。事務中包含的各項操作在一次執行過程中,只允許出現兩種狀態之一。
- 全部執行成功
- 全部執行失敗
任何一項操作失敗都會導致整個事務的失敗,同時其它已經被執行的操作都將被撤銷並回滾,只有所有的操作全部成功,整個事務纔算是成功完成。
2.2. 一致性(Consistency)
事務的一致性是指事務的執行不能破壞數據庫數據的完整性和一致性,一個事務在執行之前和執行之後,數據庫都必須處以一致性狀態。
比如:如果從A賬戶轉賬到B賬戶,不可能因爲A賬戶扣了錢,而B賬戶沒有加錢。
2.3 隔離性
事務的隔離性是指在併發環境中,併發的事務是互相隔離的,一個事務的執行不能被其它事務干擾。也就是說,不同的事務併發操作相同的數據時,每個事務都有各自完整的數據空間
。
一個事務內部的操作及使用的數據對其它併發事務是隔離的,併發執行的各個事務是不能互相干擾的。
在標準SQL規範中,定義了4個事務隔離級別,不同的隔離級別對事務的處理不同。4個隔離級別分別是:
- 讀未提及(READ_UNCOMMITTED)
- 讀已提交(READ_COMMITTED)
- 可重複讀(REPEATABLE_READ)
- 順序讀 (SERIALIZABLE)
2.4. 持久性(Duration)
事務的持久性是指事務一旦提交後,數據庫中的數據必須被永久的保存下來。即使服務器系統崩潰或服務器宕機等故障。只要數據庫重新啓動,那麼一定能夠將其恢復到事務成功結束後的狀態。
3. 事物的四種隔離特性可能帶來的問題
事物在多併發時可能出現以下問題:
-
髒讀
事務A修改了一個數據,但未提交,事務B讀到了事務A未提交的更新結果,如果事務A提交失敗,事務B讀到的就是髒數據。
-
不可重複讀
同一個事務多次讀取同一份數據,讀取到的結果不一致。比如,事務B在事務A提交前讀到的結果,和提交後讀到的結果可能不同。
-
幻讀
在同一個事務中,同一個查詢多次返回的結果不一致。事務A新增了一條記錄,事務B在事務A提交前後各執行了一次查詢操作,發現後一次比前一次多了一條記錄。
這和事物的隔離特性息息相關,因此下文將以四種隔離特性淺談髒讀、幻讀以及不可重複讀問題。
3.1 讀未提交(READ_UNCOMMITTED)
讀未提交,該隔離級別允許髒讀取,其隔離級別是最低的。換句話說,如果一個事務正在處理某一數據,並對其進行了更新,但同時尚未完成事務,因此還沒有提交事務;而以此同時,允許另一個事務也能夠訪問該數據。即事物執行的時候允許訪問尚未提交的事物
。這可能導致髒讀。
髒讀
示例
在事務A和事務B同時執行時可能會出現如下場景:
時間 | 事務A(存款) | 事務B(取款) |
---|---|---|
T1 | 開始事務 | —— |
T2 | —— | 開始事務 |
T3 | —— | 查詢餘額(1000元) |
T4 | —— | 取出1000元(餘額0元) |
T5 | 查詢餘額(0元) | —— |
T6 | —— | 撤銷事務(餘額恢復1000元) |
T7 | 存入500元(餘額500元) | —— |
T8 | 提交事務 | —— |
餘額應該爲1500元纔對。請看T5時間點,事務A此時查詢的餘額爲0,這個數據就是髒數據,他是事務B造成的,很明顯是事務沒有進行隔離造成的。
3.2 讀已提交(READ_COMMITTED)
讀已提交是不同的事物執行的時候只能獲取到已經提交的數據
。這樣就不會出現上面的髒讀的情況了。
讀已提交解決了髒讀問題,但是還是解決不了可重複讀問題。
不可重複讀
實例
時間 | 事務A(存款) | 事務B(取款) |
---|---|---|
T1 | 開始事務 | —— |
T2 | —— | 開始事務 |
T3 | —— | 查詢餘額(1000元) |
T4 | 查詢餘額(1000元) | —— |
T5 | —— | 取出1000元(餘額0元) |
T6 | —— | 提交事務 |
T7 | 查詢餘額(0元) | —— |
T8 | 提交事務 | —— |
事務A其實除了查詢兩次以外,其它什麼事情都沒做,結果錢就從1000變成0了,這就是不可重複讀的問題。
3.3 可重複讀(REPEATABLE_READ)
可重複讀就是保證在事務處理過程中,多次讀取同一個數據時,該數據的值和事務開始時刻是一致的。因此該事務級別限制了不可重複讀取和髒讀,但是有可能出現幻讀的數據。
幻讀
示例
幻讀就是指同樣的事務操作,在前後兩個時間段內執行對同一個數據項的讀取,可能出現不一致的結果。
時間 事務A | (統計總存款) | 事務B(存款) |
---|---|---|
T1 | 開始事務 | —— |
T2 | —— | 開始事務 |
T3 | 統計總存款(1000元) | —— |
T4 | —— | 存入100元 |
T5 | —— | 提交事務 |
T6 | 提交總存款(1100) | —— |
T7 | 提交事務 | —— |
銀行工作人員在一個事務中多次統計總存款時看到結果不一樣。如果要解決幻讀,那隻能使用順序讀了。
3.4 順序讀(SERIALIZABLE)
順序讀是最嚴格的事務隔離級別。它要求所有的事務排隊順序執行,即事務只能一個接一個地處理,不能併發
。
3.5 總結
事務隔離級別對比
事務隔離級別 | 髒 讀 | 不可重複讀 | 幻 讀 | 併發模型 | 更新衝突檢測 |
---|---|---|---|---|---|
讀未提及(READ_UNCOMMITTED) | 允許 | 允許 | 允許 | 悲觀 | X |
讀已提交(READ_COMMITTED ) | 禁止 | 允許 | 允許 | 悲觀 | X |
可重複讀(REPEATABLE_READ) | 禁止 | 禁止 | 允許 | 悲觀 | X |
順序讀(SERIALIZABLE) | 禁止 | 禁止 | 禁止 | 悲觀 | X |
4種事務隔離級別從上往下,級別越高,併發性越差,安全性就越來越高。
一般數據默認級別是讀以提交或可重複讀。