atomic(原子性):事務中所有的操作是一個整體單元,這個單元中的操作要麼全部成功,要麼全部失敗,不會出現部分失敗、部分成功的場景;
consistency(一緻性):事務在完成時,必須使所有的資料都保持一緻的狀态(限制 a + b = 10,事務結束後 a + b = 10 仍然成立);
isolation(隔離性):各個事務在一定程度上感覺不到其他事務的存在(展現在不同的隔離級别上);
durability(持久性):事務送出後,所有的資料都會永久寫入到磁盤。
資料庫标準提出了 4 類隔離級别,在不同程度上壓制更新丢失。
讀未送出
讀已送出
可重複讀
串行化
讀未送出(read uncommitted) 是最低的隔離級别,允許一個事務讀取另一個事務沒有送出的資料。适合對于資料一緻性沒有要求的場景。它存在髒讀的現象,如下表:
時刻
事務 1
事務 2
說明
t1
讀取庫存為 2
庫存為 2
t2
庫存 - 1
庫存為 1
t3
庫存為 0(讀取到事務 1 沒有送出的資料)
t4
送出事務
庫存儲存為 0
t5
復原
庫存為 0(第一類丢失更新已經克服)
第一類丢失更新:一個事務復原,另一個事務送出,復原覆寫了送出的資料。目前的資料庫都克服了第一類丢失更新。
讀已送出(read committed) 是指一個事務隻能讀取另一個事務已送出的資料,不能讀取未送出的資料。
事務 1 中庫存為 1
事務 2 中庫存為 1(事務 1 未送出)
送出
庫存儲存為 1
復原事務
庫存為 1 (第一類丢失更新已經克服)
上表中的操作結果最終正确。但是讀已送出會産生不可重複讀:
讀取庫存為 1
事務 1 中庫存為 0
事務 2 認為可以扣減(事務 1 未送出)
失敗,此時庫存為 0
這裡事務 2 在事務 1 送出之前認為可以扣減,而後來事務 2 扣減時發現庫存已經為 0 無法扣減,這樣的現象稱為不可重複讀,這就是讀已送出的一個不足。
可重複讀(read repeatable) 的目标是克服讀已送出中出現的不可重複讀的現象。
讀取庫存
事務 2 不能讀取,等待事務 1 送出
庫存為 0,無法扣減
當事務 2 讀取事務 1 事先讀取的資料時,會被阻塞,直到事務 1 送出後事務 2 才能讀取,讀已送出中出現的不可重複讀現象消失了。但是可重複讀會出現幻讀:
查詢庫存 100
庫存 100,10 個訂單
查詢訂單為 10
插入訂單
庫存 99,11 個訂單
t6
列印訂單,11 單
事務 2 中多了一條記錄,與之前查詢的不一緻
上表出現的就是幻讀現象,幻讀不是針對一條資料庫記錄而言,而是多條記錄,上表中訂單是多條記錄統計出來的,它會産生幻讀。
串行化(serializable) 是資料庫最高的隔離級别,所有的事務都按順序執行。它可以克服前面的隔離級别中出現的各種問題,能夠完全保證資料的一緻性。
隔離級别
髒讀
不可重複讀
幻讀
√
×
不同的隔離級别能夠在不同程度上壓制丢失更新,使用更高的隔離級别能夠更好地保證資料的一緻性,但是也要付出性能的代價。隔離級别越高,性能越是直線地下降。