數據庫標準提出了 4 類隔離級別,在不一樣程度上壓制更新丟失。數據庫
讀未提交(read uncommitted) 是最低的隔離級別,容許一個事務讀取另外一個事務沒有提交的數據。適合對於數據一致性沒有要求的場景。它存在髒讀的現象,以下表:性能
時刻 | 事務 1 | 事務 2 | 說明 |
---|---|---|---|
T1 | 讀取庫存爲 2 | 庫存爲 2 | |
T2 | 庫存 - 1 | 庫存爲 1 | |
T3 | 庫存 - 1 | 庫存爲 0(讀取到事務 1 沒有提交的數據) | |
T4 | 提交事務 | 庫存保存爲 0 | |
T5 | 回滾 | 庫存爲 0(第一類丟失更新已經克服) |
第一類丟失更新:一個事務回滾,另外一個事務提交,回滾覆蓋了提交的數據。目前的數據庫都克服了第一類丟失更新。事務
讀已提交(read committed) 是指一個事務只能讀取另外一個事務已提交的數據,不能讀取未提交的數據。ci
時刻 | 事務 1 | 事務 2 | 說明 |
---|---|---|---|
T1 | 讀取庫存爲 2 | 庫存爲 2 | |
T2 | 庫存 - 1 | 事務 1 中庫存爲 1 | |
T3 | 庫存 - 1 | 事務 2 中庫存爲 1(事務 1 未提交) | |
T4 | 提交 | 庫存保存爲 1 | |
T5 | 回滾事務 | 庫存爲 1 (第一類丟失更新已經克服) |
上表中的操做結果最終正確。可是讀已提交會產生不可重複讀:it
時刻 | 事務 1 | 事務 2 | 說明 |
---|---|---|---|
T1 | 讀取庫存爲 1 | 庫存爲 1 | |
T2 | 庫存 - 1 | 事務 1 中庫存爲 0 | |
T3 | 讀取庫存爲 1 | 事務 2 認爲能夠扣減(事務 1 未提交) | |
T4 | 提交 | 庫存保存爲 0 | |
T5 | 庫存 - 1 | 失敗,此時庫存爲 0 |
這裏事務 2 在事務 1 提交以前認爲能夠扣減,然後來事務 2 扣減時發現庫存已經爲 0 沒法扣減,這樣的現象稱爲不可重複讀,這就是讀已提交的一個不足。io
可重複讀(read repeatable) 的目標是克服讀已提交中出現的不可重複讀的現象。table
時刻 | 事務 1 | 事務 2 | 說明 |
---|---|---|---|
T1 | 讀取庫存爲 1 | 庫存爲 1 | |
T2 | 庫存 - 1 | 事務 1 中庫存爲 0 | |
T3 | 讀取庫存 | 事務 2 不能讀取,等待事務 1 提交 | |
T4 | 提交 | 庫存保存爲 0 | |
T5 | 讀取庫存 | 庫存爲 0,沒法扣減 |
當事務 2 讀取事務 1 事先讀取的數據時,會被阻塞,直到事務 1 提交後事務 2 才能讀取,讀已提交中出現的不可重複讀現象消失了。可是可重複讀會出現幻讀:class
時刻 | 事務 1 | 事務 2 | 說明 |
---|---|---|---|
T1 | 查詢庫存 100 | 庫存 100,10 個訂單 | |
T2 | 查詢訂單爲 10 | ||
T3 | 庫存 - 1 | ||
T4 | 插入訂單 | ||
T5 | 提交 | 庫存 99,11 個訂單 | |
T6 | 打印訂單,11 單 | 事務 2 中多了一條記錄,與以前查詢的不一致 |
上表出現的就是幻讀現象,幻讀不是針對一條數據庫記錄而言,而是多條記錄,上表中訂單是多條記錄統計出來的,它會產生幻讀。統計
串行化(serializable) 是數據庫最高的隔離級別,全部的事務都按順序執行。它能夠克服前面的隔離級別中出現的各類問題,可以徹底保證數據的一致性。總結
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
讀未提交 | √ | √ | √ |
讀已提交 | × | √ | √ |
可重複讀 | × | × | √ |
串行化 | × | × | × |
不一樣的隔離級別可以在不一樣程度上壓制丟失更新,使用更高的隔離級別可以更好地保證數據的一致性,可是也要付出性能的代價。隔離級別越高,性能越是直線地降低。