2.1 讀未提交

“事務隔離級別”是指DBMS內部機制(即不需要特殊編程)對事務並行執行時出現的上述所有或部分類型的數據不一致的保護程度。SQL-92 標准定義了四個隔離級別的範圍:

  • 讀取未提交
  • 讀提交
  • 可重複讀
  • 可序列化

第一個是最弱的,最後一個是最強的,後面的每一個都包含了前面的所有。

最低(第一)隔離級別。如果多個並行事務試圖修改同一個表行,那麼最後一行的值將由整個成功完成的事務集決定。在這種情況下,不僅可以讀取邏輯上不一致的數據,還可以讀取尚未記錄更改的數據。

實現此隔離級別的典型方法是在執行更改命令時鎖定數據,這可確保並行運行的相同行上的修改命令實際上是按順序執行的,並且不會丟失任何更改。只讀事務永遠不會在此隔離級別下阻塞。

2.2 讀提交

大多數工業 DBMS,特別是 Microsoft SQL Server、PostgreSQL 和 Oracle,默認使用此級別。在這個級別,提供了防止草稿、“臟”讀的保護,但是,在一個事務的運行過程中,另一個事務可以成功完成,並且它所做的更改是固定的。因此,第一個事務將使用不同的數據集。

完整讀取的實現可以基於以下兩種方法之一:阻塞或版本控制。

阻塞可讀和可變數據。

它包括這樣一個事實,即寫入事務阻塞可變數據以讀取在讀取提交級別或更高級別操作的事務,直到它完成,從而防止“臟”讀取,並且讀取事務鎖定的數據在操作完成後立即釋放SELECT(因此,在給定的隔離級別上可能會出現“不可重複讀取”的情況)。

保存並行更改的多個版本的行。

每次更改一行時,DBMS 都會創建該行的一個新版本,更改數據的事務將繼續使用該行,而任何其他“讀取”事務將返回最後提交的版本。這種方法的優點是速度更快,因為它可以防止阻塞。但是,與第一個相比,它需要更多的 RAM 消耗,這些 RAM 用於存儲行版本。

此外,當多個事務並行更改數據時,可能會造成多個並發事務對同一數據進行不一致更改的情況(因為沒有鎖,所以沒有什麼可以阻止這種情況的發生)。那麼最先提交的事務會將其更改保存在主數據庫中,其餘並行事務將無法提交(因為這會導致第一個事務的更新丟失)。在這種情況下,DBMS 唯一能做的就是回滾其餘事務並發出錯誤消息“記錄已被更改”。

具體的實現方法由 DBMS 開發人員選擇,在某些情況下可以定制。因此,默認情況下,MS SQL 使用鎖,但(在 2005 及更高版本中)在設置READ_COMMITTED_SNAPSHOT數據庫參數時,它切換到版本控制策略,Oracle 最初僅根據版本控制方案工作。USELASTCOMMITTED在 Informix 中,您可以通過設置一個配置選項(自版本 11.1 起)使讀取事務接收最新提交的數據來防止讀取和寫入事務之間的衝突。

2.3 可重複讀

讀取事務“看不到”的級別改變了它之前讀取的數據。同時,任何其他事務都不能改變當前事務讀取的數據,直到它結束。

共享模式下的鎖應用於事務中任何指令讀取的所有數據,並一直保持到事務完成。這可以防止其他事務修改掛起事務讀取的行。但是,其他事務可能會插入與當前事務中包含的指令的搜索條件相匹配的換行符。當前事務重新啟動該語句時,將獲取新行,從而導致幻讀。

鑑於共享鎖一直持有到事務結束,而不是在每條語句結束時釋放,因此並發度低於隔離級別READ COMMITTED。因此,一般不建議不必要地使用這個和更高的事務級別。

2.4 可序列化

最高級別的隔離;事務彼此完全隔離,每個事務都像沒有並行事務一樣執行。只有在這個級別,並發事務才不會受到“幻讀”的影響。

2.5 支持真實DBMS中的事務隔離

事務型 DBMS 並不總是支持所有四個級別,還可能引入其他級別。在提供絕緣方面也有各種細微差別。

所以,Oracle原則上是不支持零級別的,因為它對事務的實現排除了“臟讀”,並且正式不允許設置Repeatable read級別,即它只支持(默認)Read committedSerializable。同時,在單個命令的層面上,它實際上保證了讀取可重複性(如果SELECT第一個事務中的一個命令從數據庫中選擇了一組行,此時並行的第二個事務更改了其中的一些行,那麼第一個事務收到的結果集將包含未更改的行,就好像沒有第二個事務一樣)。Oracle 還支持所謂的READ-ONLY事務,它對應於Serializable,但不能更改數據本身。

並且Microsoft SQL Server支持所有四種標準事務隔離級別,此外還支持 SNAPSHOT 級別,在該級別事務可以看到在它啟動之前提交的數據狀態,以及它自己所做的更改,即它的行為如下如果它在啟動時接收到數據庫數據的快照並使用它。與 Serialized 的區別在於沒有使用鎖,但是如果並發事務之前更改過相同的數據,則可能無法提交更改;在這種情況下,第二個事務在嘗試執行時COMMIT將引發錯誤消息並被取消。