淺談Sql 中的鎖
轉自:http://blog.csdn.net/abrahamcheng/article/details/6216428
淺談Sql 中的鎖
1.鎖的概念
Sql server 使用鎖來確保事務的獨立性,鎖可以為某個事務鎖定資源,防止事務間就訪問統一資源的發生衝突,如多個事務同時請求更新某條記,當某個事務開始時就lock住它要更新的記錄,直到該事務結束 (unblock) 釋放該資源, 這樣其他事務在請求更新該記錄時就會被block, 直到佔用該資源的事務結束才有可能unblock.
2.鎖的模式和相容性
鎖一般可以分為排他鎖和共享鎖,當需要更新,刪除時使用排他鎖,當僅僅要讀某個資源時使用的是共享鎖。因此排他鎖又稱之為寫鎖,共享鎖又稱之為讀鎖。鎖之間的相容性是指某個資源被加了某種鎖A後能否再加其他鎖B,如果可以則成為鎖A對鎖B是相容的。
相容性 |
寫鎖 |
讀鎖 |
寫鎖 |
No |
No |
讀鎖 |
No |
Yes |
由上表可見僅共享鎖是相容共享鎖的。
3.可以被鎖的資源型別(鎖的粒度)
Sql Server 可以鎖定不同的資源型別,或者說鎖的粒度是不同的。 這些資源的型別可以有:RID or key (row), page, object (for example, table), database。 但row是屬於某個page的,page 又是屬於某個block(儲存塊)的 ……, 因此當要鎖(exclusive lock)定一格row時,先要用意向鎖(intent exclusive lock)鎖定該row的上一層粒度page. 同樣讀取某個記錄時在加共享鎖之前也要先給對的的page加共享意向鎖(intent share lock).
Requested Mode |
Granted Exclusive (X) |
Granted Shared (S) |
Granted Intent Exclusive (IX) |
Granted Intent Shared (IS) |
Grant Request for Exclusive? |
No |
No |
No |
No |
Grant Request for Shared? |
No |
Yes |
No |
Yes |
Grant Request for Intent Exclusive? |
No |
No |
Yes |
Yes |
Grant Request for Intent Shared? |
No |
Yes |
Yes |
Yes |
這些鎖的粒度一般由Sql server 動態決定,鎖是要消耗資源的,一個簡單的Sql 語句可能會用到成千上萬的鎖。它們也會隨著Sql語句的執行結束而釋放它們所站的資源。
4.和鎖有關比較有幫助的Sql:
檢視所有鎖的資訊:
SELECT -- use * to explore other available attributes
request_session_id AS spid,
resource_type AS restype,
resource_database_id AS dbid,
DB_NAME(resource_database_id) AS dbname,
resource_description AS res,
resource_associated_entity_id AS resid,
request_mode AS mode,
request_status AS status
FROM sys.dm_tran_locks;
檢視對應的session:
SELECT -- use * to explore
session_id AS spid,
connect_time,
last_read,
last_write,
most_recent_sql_handle
FROM sys.dm_exec_connections
WHERE session_id = @spid
檢視session 執行的sql語句:
SELECT session_id, text
FROM sys.dm_exec_connections
CROSS APPLY sys.dm_exec_sql_text(most_recent_sql_handle) AS ST
WHERE session_id = @spid
檢視session的執行帳戶和相關資訊:
SELECT -- use * to explore
session_id AS spid,
login_time,
host_name,
program_name,
login_name,
nt_user_name,
last_request_start_time,
last_request_end_time
FROM sys.dm_exec_sessions
WHERE session_id IN(52, 53);
檢視是否有block的session:
SELECT -- use * to explore
session_id AS spid,
blocking_session_id,
command,
sql_handle,
database_id,
wait_type,
wait_time,
wait_resource
FROM sys.dm_exec_requests
WHERE blocking_session_id > 0;
設定鎖的超時時間:
SET LOCK_TIMEOUT 5000;
SET LOCK_TIMEOUT -1; // 該句鎖的超時時間設定成預設時間
終止一個session : KILL @spid;