1. 程式人生 > >SQL SERVER的鎖機制(一)——概述(鎖的種類與範圍)

SQL SERVER的鎖機制(一)——概述(鎖的種類與範圍)

row 定性 針對 共享 互斥 drop 問題 停止 共享鎖

SQL SERVER的鎖機制系列:

SQL SERVER的鎖機制(一)——概述(鎖的種類與範圍)

SQL SERVER的鎖機制(二)——概述(鎖的兼容性與可以鎖定的資源)

SQL SERVER的鎖機制(三)——概述(鎖與事務隔離級別)

SQL SERVER的鎖機制(四)——概述(各種事務隔離級別發生的影響)

鎖定:通俗的講就是加鎖。鎖定是 Microsoft SQL Server 數據庫引擎用來同步多個用戶同時對同一個數據塊的訪問的一種機制。

定義:當有事務操作時,數據庫引擎會要求不同類型的鎖定,如相關數據行、數據頁或是整個數據表,當鎖定運行時,會阻止其他事務對已經鎖定的數據行、數據頁或數據表進行操作。只有在當前事務對於自己鎖定的資源不在需要時,才會釋放其鎖定的資源,供其他事務使用。

一、鎖的種類與範圍(如下表)

鎖類型

說明

共享 (S)

用於不更改或不更新數據的讀取操作,如 SELECT 語句。

更新 (U)

用於可更新的資源中。 防止當多個會話在讀取、鎖定以及隨後可能進行的資源更新時發生常見形式的死鎖。

獨占(也可稱排他)(X)

用於數據修改操作,例如 INSERT、UPDATE 或 DELETE。 確保不會同時對同一資源進行多重更新。

意向

用於建立鎖的層次結構。 意向鎖包含三種類型:意向共享 (IS)、意向排他 (IX) 和意向排他共享 (SIX)。

架構

在執行依賴於表架構的操作時使用。 架構鎖包含兩種類型:架構修改 (Sch-M) 和架構穩定性 (Sch-S)。

大容量更新 (BU)

在向表進行大容量數據復制且指定了 TABLOCK 提示時使用。

鍵範圍

當使用可序列化事務隔離級別時保護查詢讀取的行的範圍。 確保再次運行查詢時其他事務無法插入符合可序列化事務的查詢的行。

(一)共享鎖

共享鎖(S 鎖)允許並發事務在封閉式並發控制下讀取 (SELECT) 資源。

當查詢(SELECT)某條記錄時,SQL SERVER 會嘗試取得該條記錄的上存在共享鎖(S 鎖),或無法獲取,就必須等待別人釋放對該記錄中某幾種與共享鎖互斥的鎖,才能在設置共享鎖之後,獲取該條記錄。

舉例來說:當某人查詢某張表的一條記錄時,就會在該記錄上放置共享鎖,在而其他人也要查詢這張表的此記錄時,因為共享鎖彼此不互斥,所以也可以再次放置共享鎖,也就是說SQL SERVER允許不同連接同時讀取相同的數據。如果此時有人要更新此記錄,因為獨占鎖與共享鎖互斥,所以無法放置獨占鎖,要等到所有讀取此記錄的人都讀取完畢,釋放了共享鎖,更新數據的人才能對該記錄設置獨占鎖,並進一步更新數據。一般情況下,在默認的事務隔離級別下,當數據讀取完畢,SQL SERVER就會釋放共享鎖,除非有特別的設置。

(二)更新鎖

更新鎖是一種中繼鎖。當同一項資源從原來的查詢操作轉換為更新操作時,鎖定機制會從共享鎖變為更新鎖,再進一步變成獨占鎖。

在可重復讀或可序列化事務中,此事務讀取數據 [獲取資源(頁或行)的共享鎖(S 鎖)],然後修改數據 [此操作要求鎖轉換為獨占鎖(X 鎖)]。 如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新數據,則一個事務嘗試將鎖轉換為獨占鎖(X 鎖)。 共享模式到獨占鎖的轉換必須等待一段時間,因為一個事務的獨占鎖與其他事務的共享模式鎖不兼容;發生鎖等待。 第二個事務試圖獲取獨占鎖(X 鎖)以進行更新。 由於兩個事務都要轉換為獨占鎖(X 鎖),並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。

若要避免這種潛在的死鎖問題,請使用更新鎖(U 鎖)。 一次只有一個事務可以獲得資源的更新鎖(U 鎖)。 如果事務修改資源,則更新鎖(U 鎖)轉換為獨占鎖(X 鎖)。

例如,當查詢一條記錄後,要將此內容更新(Update語句加上Where條件),一定會先查找記錄,在查找的過程中就會對相關的記錄放置共享鎖,等找到相應的記錄之後,SQL SERVER 會先對記錄放置更新鎖,以避免發生死鎖。因為共享鎖與更新鎖並不互斥,如果兩個人同時對同一條記錄放置共享鎖,先進行更新的人,可以在別人也對同一條記錄放置了共享鎖時,繼續放置更新鎖,但因為更新鎖互斥,所以當另一個人想再放置更新鎖時,將無法設置,而進入停止等待狀態。

(三)獨占鎖(也可稱為排他鎖)

獨占鎖(排他鎖)(X 鎖)可以防止並發事務對資源進行訪問。 使用獨占鎖(X 鎖)時,任何其他事務都無法修改數據;僅在使用 NOLOCK 提示或未提交讀隔離級別時才會進行讀取操作。

對數據進行添加、修改、刪除操作時(如 INSERT、UPDATE 和 DELETE), 語句在執行所需的操作之前首先執行讀取操作以獲取數據。 因此,需先對所在的資源放置獨占鎖,以確保以上操作未完成時,不受到幹擾,獨占鎖在開啟事務之後,一直保留到事務結束。例如,UPDATE 語句可能根據與一個表的聯接修改另一個表中的行。 在此情況下,除了請求更新行上的獨占鎖之外,UPDATE 語句還將請求在聯接表中讀取的行上的共享鎖。

(四)意向鎖

在記錄上放置共享鎖之前,需要對存放該記錄的更大範圍(如數據頁或數據表)上設置意向鎖,以避免其他連接對該頁放置獨占鎖。

數據庫引擎使用意向鎖來保護共享鎖(S 鎖)或獨占鎖(X 鎖)放置在鎖層次結構的底層資源上。 意向鎖之所以命名為意向鎖,是因為在較低級別鎖前可獲取它們,因此會通知意向將鎖放置在較低級別上。

意向鎖有兩種用途:

· 防止其他事務以會使較低級別的鎖無效的方式修改較高級別資源。

· 提高數據庫引擎在較高的粒度級別檢測鎖沖突的效率。

例如,在該表的數據頁或數據行上請求共享鎖(S 鎖)之前,在表級(或頁級)請求共享意向鎖,以防止另一個事務隨後在包含那一頁的表上嘗試放置獨占鎖(X 鎖)。 意向鎖可以提高性能,因為數據庫引擎僅在表級檢查意向鎖來確定事務是否可以安全地獲取該表上的鎖。 而不需要檢查表中的每行或每頁上的鎖以確定事務是否可以鎖定整個表。如下圖。

意向鎖包括意向共享 (IS)、意向排他 (IX) 以及意向排他共享 (SIX)等等。各種意向鎖的說明,如下表。

鎖類型

說明

意向共享 (IS)

保護針對層次結構中某些(而並非所有)低層資源請求或獲取的共享鎖。

意向獨占 (IX)

保護針對層次結構中某些(而並非所有)低層資源請求或獲取的獨占鎖。 IX 是 IS 的超集,它也保護針對低層級別資源請求的共享鎖。

意向獨占共享 (SIX)

保護針對層次結構中某些(而並非所有)低層資源請求或獲取的共享鎖以及針對某些(而並非所有)低層資源請求或獲取的意向獨占鎖。 頂級資源允許使用並發 IS 鎖。 例如,獲取表上的 SIX 鎖也將獲取正在修改的頁上的意向獨占鎖以及修改的行上的獨占鎖。 雖然每個資源在一段時間內只能有一個 SIX 鎖,以防止其他事務對資源進行更新,但是其他事務可以通過獲取表級的 IS 鎖來讀取層次結構中的低層資源。

意向更新 (IU)

保護針對層次結構中所有低層資源請求或獲取的更新鎖。 僅在頁資源上使用 IU 鎖。 如果進行了更新操作,IU 鎖將轉換為 IX 鎖。

共享意向更新 (SIU)

S 鎖和 IU 鎖的組合,作為分別獲取這些鎖並且同時持有兩種鎖的結果。 例如,事務執行帶有 PAGLOCK 提示的查詢,然後執行更新操作。 帶有 PAGLOCK 提示的查詢將獲取 S 鎖,更新操作將獲取 IU 鎖。

更新意向排他 (UIX)

U 鎖和 IX 鎖的組合,作為分別獲取這些鎖並且同時持有兩種鎖的結果。

下面來實際舉例來說明

復制代碼
--示例代碼一:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

BEGIN TRAN

SELECT * FROM [Book] WHERE [bookid]=1

WAITFOR DELAY ‘00:00:10‘

COMMIT TRAN
復制代碼

可以通過另一條連接執行SP_LOCK 來查看上面代碼的執行結果,如下圖。在數據表上與數據頁上都放置了意向共享鎖,而在鎖定的記錄上放置了共享鎖。

復制代碼
--示例代碼二:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

BEGIN TRAN

SELECT * FROM [WBK_PDE_LIST] WHERE [WBOOK_NO]=‘BE404942450020‘ and cop_g_no=‘60217445‘

WAITFOR DELAY ‘00:00:10‘

COMMIT TRAN
復制代碼

可以通過另一條連接執行SP_LOCK 來查看上面代碼的執行結果,如下圖。由於上述代碼中的[WBK_PDE_LIST]是一張堆表,所以直接就對數據表加了共享鎖。

對上述示例中表WBK_PDE_LIST添加索引,

復制代碼
CREATE NONCLUSTERED INDEX [IX_WBK_PDE_LIST_WBOOKNO] ON [dbo].[WBK_PDE_LIST]

(

[WBOOK_NO] ASC,

[COP_G_NO] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF

, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
復制代碼

然後再次執行代碼示例二,再打開一個新的查詢分析器,在查詢分析器中執行SP_LOCK 來查看上面代碼的執行結果,如下圖。在數據表與數據頁上分別放置了意向共享鎖,在索引與數據行上放置了共享鎖。

(五)架構鎖

數據庫引擎在表數據定義語言 (DDL) 操作(例如添加列或刪除表)的過程中使用架構修改 (Sch-M) 鎖。 保持該鎖期間,Sch-M 鎖將阻止對表進行並發訪問。 這意味著 Sch-M 鎖在釋放前將阻止所有外圍操作。

某些數據操作語言 (DML) 操作(例如表截斷)使用 Sch-M 鎖阻止並發操作訪問受影響的表。

數據庫引擎在編譯和執行查詢時使用架構穩定性 (Sch-S) 鎖。 Sch-S 鎖不會阻止某些事務鎖,其中包括排他 (X) 鎖。 因此,在編譯查詢的過程中,其他事務(包括那些針對表使用 X 鎖的事務)將繼續運行。 但是,無法針對表執行獲取 Sch-M 鎖的並發 DDL 操作和並發 DML 操作。

(六)大容量更新鎖

數據庫引擎在將數據大容量復制到表中時,指定 TABLOCK 提示或使用 sp_tableoption 選項(將數據表設置為 table lock on bulk load),則是使用大容量更新鎖(BU)。 大容量更新鎖(BU 鎖)允許多個線程將數據並發地大容量加載到同一表,以降低數據表的鎖定競爭,同時防止其他不進行大容量加載數據的進程訪問該表。

(七)鍵範圍鎖

在使用可序列化事務隔離級別時,保護用戶對於查詢時所讀取的數據行範圍,以確保其他事務無法插入受“鍵範圍鎖”保護的數據行。鍵範圍鎖放置在索引上,指定開始與結束的索引鍵值。這些操作會先在索引上獲取鎖定,此種鎖定可以封鎖任何嘗試進行插入、修改、刪除索引鍵值在“鍵範圍鎖”中的數據行。例如:在索引鍵值“AAA”至“CZZ”範圍中放置鍵範圍鎖,避免其他事務將含有索引鍵值的數據行插入到該範圍內的任何地方,例如:“ABC”、“BCD”、“CEF”。另外當UPDATE語句搭配WHERE子句時,當SQL SERVER還在查找數據時,也有可能會設置鍵範圍鎖。

SQL SERVER的鎖機制(一)——概述(鎖的種類與範圍)