上一篇SQL Server詳細講解了隔離級别,但是對基于行版本中的SNAPSHOT隔離級别仍未完全了解,本節再詳細講解下,若有疑義或不同見解請在評論中提出,一起探讨。
在SNAPSHOT隔離級别下,讀取者在讀取資料時, 它是確定獲得事務啟動時最近送出的可用行版本,這意味着,保證獲得的是送出後的讀取并且可重複讀取,以及確定獲得不是幻讀,類似于SERIALIZABLE級别中一樣,但是此隔離級别依賴于行版本,而不是使用共享鎖,要想在企業部署的SQL Server執行個體中允許事務以SNAPSHOT隔離級别工作,首先需要在查詢視窗執行以下代碼打開快照隔離級别。如下:
下面我們再用一個簡單的例子來詳細講解其過程。首先我們啟用上述SNAPSHOT隔離級别,然後查詢某個表的修改日期列,如下:

如上是我們正常查詢出的修改日期列(ModifiedDate)。接下來我們建立兩個會話,一個是寫入會話(會話一),另外一個是查詢會話(會話二)來證明SNAPSHOT隔離級别的作用。
我們設定寫入者的隔離級别為SNAPSHOT,然後更新其修改日期為目前日期,但是我們此時隻是開啟了事務并未送出該寫入事務。與此同時我們再來建立一個查詢會話(會話二)來查詢修改日期列,如下查詢會話也未送出事務。
此時我們看到查詢出的修改日期依然是原始值并未進行修改,此時我們再來送出寫入者事務(會話一),在上述寫入者事務後面添加如下一句。
此時再來在會話二中查詢修改日期,結果依然是原始值,如下:
此時我們再來送出查詢事務(會話二),再來查詢,結果如下
在上一篇僅僅隻講述了最後結果的變化,并未叙述其中過程到底是怎樣的,請往下看。
(1)會話一中開啟事務并更新修改日期列,但是并未送出會話一中的事務,換句話說,原始值将依然有效,是以SNAPSHOT(快照隔離級别)導緻仍然可以讀取到原始值。
(2)會話二中開啟事務并讀取原始值,在這個階段中,資料庫引擎将建立一個讀取的行副本到tempdb臨時資料庫中,是以在會話二中的所有讀取事務都将從tempdb臨時資料庫中讀取。
(3)會話一送出了事務并将其修改的值儲存到了表中,注意,此時改變的值隻是響應到了表中,而會話二中在tempdb臨時資料庫中副本依然保持不變。
(4)會話二再次讀取行時,此時将從tempdb臨時資料庫中去讀取且讀取到的依然是原始值,因為在會話二中還并未送出事務。
(5)會話二送出了事務,此時将銷毀在tempdb臨時資料庫中的副本,在此之後将無法再讀取原始值。
(6)會話二再次讀取行時,因為在送出事務之後在tempdb臨時資料庫中沒有行,是以現在将去表中擷取新行。
若我們在上述會話二中查詢并未開啟事務,這就意味着所有讀取将直接從表中讀取,同時将不會建立副本到tempdb臨時資料庫中,進一步講,此時将導緻查詢阻塞,是以從這裡我們知道開啟基于行版本的SNAPSHOT隔離級别将有利于減少死鎖情況的發生,提高并發性能。
本節我們再次很詳細講解了基于行版本的SNAPSHOT隔離級别的過程描述,總算是明白了基于行版本隔離級别的原理。