1. 程式人生 > >SQL Server 之 事務與隔離級別實例講解

SQL Server 之 事務與隔離級別實例講解

數據 potential ola sed http 高可用 獲取 簡介 set

原文:SQL Server 之 事務與隔離級別實例講解

  SQL Server 實現了6個隔離級別來防止並發情況下,類似企圖並發的訪問或修改同一數據時問題的發生。本文將帶你體驗全部6個隔離級別。正如你接下來將看到的,你將理解每個隔離級別所能達成的效果以及何時使用它。

一、事務簡介

  SQL Server的6個隔離級別中有5個是用於隔離事務的,它們因而被稱作事務隔離級別。另外的一個工作於語句級別。

  在現實中要求多個數據修改操作必須要麽完全成功要麽什麽也沒發生的例子。當數據被合並到數據庫時,可能有多個表需要更新。當顧客下訂單時,Order表、Invoice Line Item表和Product表的數據可能都需要更新。購買機票也許要求更新Passenger表和Reservations表。無論何時當一個操作要求多個數據更改操作整體地作為單一的單元來處理,這就是需要使用事務的時候。

  如果事務中所有的數據更改操作都成功了,那麽這些數據更改就可以被提交(也就是持久化到數據庫)。否則,截止到失敗點事務中所發生的所有數據更改必須被回滾(也就是撤銷操作,什麽也不曾發生)。
  事務相關操作,參照 http://www.cnblogs.com/xinaixia/p/4831198.html 。

二、 隔離級別簡介

  必須小心對待並發情況,因為它們可能引發已知的並發性問題,包括“臟讀”、“不可重復讀”和“幻像讀”,這些問題可能反過來導致數據的不良後果。正如我們已經知道的,為了防止並發性問題,隔離級別用於將事務或語句相互間隔離開來。

  下面是SQL Server 2008中定義的隔離級別名稱:

  1、Transaction Isolation Level

  [1] READ UNCOMMITTED  (未提交讀,讀臟),相當於(NOLOCK)
  [2] READ COMMITTED (Default)  (已提交讀,默認級別)
  [3] REPEATABLE READ  (可以重復讀),相當於(HOLDLOCK)
  [4] SERIALIZABLE  (可序列化)
  [5] SNAPSHOT  (快照)

  2、Statement Isolation Level

  [6] READ COMMITTED SNAPSHOT  (已經提交讀隔離)


  對於前四個隔離級別:READ UNCOMMITTED < READ COMMITTED < REPEATABLE READ < SERIALIZABLE
  隔離級別越高,讀操作的請求鎖定就越嚴格,鎖的持有時間久越長;所以隔離級別越高,一致性就越高,並發性就越低,同時性能也相對影響越大。

  獲取事務隔離級別(isolation level)

DBCC USEROPTIONS 

  設置隔離

設置會話隔離
SET TRANSACTION ISOLATION LEVEL <ISOLATION NAME>
--註意:在設置回話隔離時(REPEATABLE READ)兩個單詞需要用空格間隔開,但是在表隔離中可以粘在一起(REPEATABLEREAD)

設置查詢表隔離
SELECT ....FROM <TABLE> WITH (<ISOLATION NAME>) 

  正如你在下面的例子中即將看到的,隔離級別越高,提供的保護級別也越高(防止更多的並發性問題)。並且,每個隔離級別包括了前一個級別所提供的保護,因此,每個後續的更高隔離級別以避免更多並發性問題的形式提供了額外的保護。但是,世上沒有免費的午餐,隔離級別越高,數據可用性就越低。選擇合適的隔離級別是一種在高度安全的並發性和數據的高可用性之間尋求平衡的行為。

三、引入實例

  為了創建並發環境,所有例子使用2個SQL Server Session,每個會話運行一個不同的事務,每個事務訪問相同的資源。在SQL Server Management Studio中,每個查詢窗口代表了一個不同的Session,因此,你可以在SQL Server Management Studio中為不同的事務使用不同的查詢窗口。
  所有例子包含了真實場景以便你將這一切建立在現實的基礎上。

  1、READ UNCOMMITTED 未提交讀

  READ UNCOMMITTED 事務隔離級別根本就沒有提供事務間的隔離,它允許違反並發性原則的最基本形式之一 -- 臟讀。當一個事務能夠讀取另一個事務中已經Update但尚未Commit的數據時,“臟讀”就發生了。READ UNCOMMITTED 讀操作不申請鎖,運行讀取未提交的修改,也就是允許讀臟數據,讀操作不會影響寫操作請求排他鎖。

  READ UNCOMMITTED 常應用於:單用戶系統;系統中兩個事務同時訪問同一資源的可能性為零或幾乎為零;當使用Rowversion數據類型控制並發性時 。

  技術分享圖片

  2、READ COMMITTED 已提交讀,默認

  通過僅允許一個事務讀取另一個事務中已經提交的數據,READ COMMITTED 事務隔離級別防止了“臟讀”問題。這是SQL Server中默認的事務隔離級別。

  它是SQL SERVER默認的隔離級別,可以避免讀取未提交的數據,隔離級別比READ UNCOMMITTED未提交讀的級別更高;該隔離級別讀操作之前首先申請並獲得共享鎖,允許其他讀操作讀取該鎖定的數據,但是寫操作必須等待鎖釋放,一般讀操作讀取完就會立刻釋放共享鎖。
  技術分享圖片

  3、REPEATABLE READ 可重復讀

  正如你在前一個事務隔離級別的步驟2所看到的,Session 2中的事務能夠修改已經被Session 1中的事務讀取的數據。正像真實場景中所描述的,這可能導致“LOST UPDATE”。REPEATABLE READ 事務隔離級別不允許這種情況發生,因為它違背了REPEATABLE READ原則。換句話說,Session 1中的事務讀取同一數據可能會產生不同的結果。

  該級別保證在一個事務中的兩個讀操作之間,其他的事務不能修改當前事務讀取的數據,該級別事務獲取數據前必須先獲得共享鎖同時獲得的共享鎖不立即釋放一直保持共享鎖至事務完成,所以此隔離級別查詢完並提交事務很重要。
  技術分享圖片

  4、SERIALIZABLE 可序列化

  對於前面的REPEATABLE READ能保證事務可重復讀,但是事務只鎖定查詢第一次運行時獲取的數據資源(數據行),而不能鎖定查詢結果之外的行,就是原本不存在於數據表中的數據。因此在一個事務中當第一個查詢和第二個查詢過程之間,有其他事務執行插入操作且插入數據滿足第一次查詢讀取過濾的條件時,那麽在第二次查詢的結果中就會存在這些新插入的數據,使兩次查詢結果不一致,這種讀操作稱之為幻讀。
  為了避免幻讀需要將隔離級別設置為 SERIALIZABLE 。為了向你展示SERIALIZABLE 事務隔離級別防止的並發性問題,本例我們從REPEATABLE READ 事務隔離級別開始。
  技術分享圖片

  SNAPSHOT 快照分為 SNAPSHOT和READ COMMITTED SNAPSHOT兩種隔離(可以把事務已經提交的行的上一版本保存在TEMPDB數據庫中):
  [1] SNAPSHOT隔離級別在邏輯上與SERIALIZABLE類似;
  [2] READ COMMITTED SNAPSHOT隔離級別在邏輯上與 READ COMMITTED類似;
  不過在快照隔離級別下讀操作不需要申請獲得共享鎖,所以即便是數據已經存在排他鎖也不影響讀操作。而且仍然可以得到和SERIALIZABLE與READ COMMITTED隔離級別類似的一致性;如果目前版本與預期的版本不一致,讀操作可以從TEMPDB中獲取預期的版本。

  如果啟用任何一種基於快照的隔離級別,DELETE和UPDATE語句在做出修改前都會把行的當前版本復制到TEMPDB中,而INSERT語句不需要在TEMPDB中進行版本控制,因為此時還沒有行的舊數據。

  無論啟用哪種基於快照的隔離級別都會對更新和刪除操作產生性能的負面影響,但是有利於提高讀操作的性能因為讀操作不需要獲取共享鎖。

  5、SNAPSHOT 快照

  也許你已經註意到,在上述例1到例4中,防止並發性問題的同時也降低了數據的可訪問性。先是不允許Read,然後是不允許Update,不允許Insert。SNAPSHOT事務隔離級別防止了之前那些隔離級別所能防止的許多並發性問題,同時降低了與之相關的成本。它允許更高的數據可用性。
  通過在事務開始前在TempDB中使用row versions創建一份數據庫的虛擬快照,SNAPSHOT事務隔離級別完成了此壯舉。此後它只允許事務訪問該數據庫虛擬快照。這種方法被稱做“基於版本控制的隔離”(versioning-based isolation)。
  使用versioning-based isolation,事務僅能看到虛擬快照中的數據。因此,其他事務仍然能夠訪問同一數據,只要它們不去修改已經被第一個事務修改過的數據就好。如果那樣做了(企圖修改數據),那麽,那些事務將會被回滾並以錯誤消息終止。
  只有當數據庫中啟用SNAPSHOT事務隔離級別的開關打開後,才能使用它。打開此開關將告知數據庫去設置版本化環境。理解這一點很重要,因為,一旦版本化開啟,數據庫會有維護版本化的開銷,無論是否有事務正在使用SNAPSHOT事務隔離級別。

  在SNAPSHOT隔離級別下,當讀取數據時可以保證操作讀取的行是事務開始時可用的最後提交版本。同時SNAPSHOT隔離級別也滿足前面的已提交讀,可重復讀,不幻讀;該隔離級別實用的不是共享鎖,而是行版本控制,使用SNAPSHOT隔離級別首先需要在數據庫級別上設置相關選項。
  技術分享圖片

  6、READ COMMITTED SNAPSHOT 提交讀快照

  到目前為止,所有的隔離級別都是將事務相互間隔離開來。一旦初始事務完成了,對其他事務變得不可用的資源才又變得可用。READ COMMITTED SNAPSHOT 隔離級別在這點上有所不同,它能夠讀取其已經被他事務提交的數據。它也是通過數據庫開關來打開的。然後,任何使用READ COMMITTED SNAPSHOT 隔離級別的事務將通過版本化起作用。

  READ COMMITTED SNAPSHOT也是基於行版本控制,但是READ COMMITTED SNAPSHOT的隔離級別是“ 讀操作之前的最後已提交版本,而不是事務前的已提交版本 ”,有點類似前面的READ COMMITTED能保證已提交讀,但是不能保證可重復讀,不能避免幻讀,但是又比 READ COMMITTED隔離級別多出了不需要獲取共享鎖就可以讀取數據。
  要啟用READ COMMITTED SNAPSHOT隔離級別同樣需要修改數據庫選項。
  技術分享圖片

四、小結

隔離級別 解決的並發性問題 存在的並發性問題
READ UNCOMMITTED 不適用於並發場合 Dirty Reads, Non-repeatable Reads, Phantom Reads
READ COMMITTED Dirty Reads Lost Update , Non-repeatable Reads, Phantom Reads
REPEATABLE READ Non-repeatable Reads Phantom Reads, potentially Deadlocking
SERIALIZABLE Phantom Reads Less Data Availability, potentially Deadlocking
SNAPSHOT 上述所有並發性問題 事務訪問的是虛擬快照,其他事務Committed的數據對當前事務仍然不可見,也不允許Update被其他事務Updated的數據。
READ COMMITTED SNAPSHOT 上述所有並發性問題
提交讀:Session1 在事物沒有執行結束的時候 Session2可以修改事物範圍內的數據。 可重復讀:Session1在事物麽有執行結束的時候 Session2不可以修改事物範圍內的數據 提交度和可重復讀都是針對於Session1來設定的 於Session2無關 參考地址:https://www.cnblogs.com/xinaixia/p/5703175.html

SQL Server 之 事務與隔離級別實例講解