首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 鎖機制深度解析:類型、粒度、模式、死鎖與自訂控制全景圖

     編輯:關於SqlServer

鎖是 SQL Server 實現悲觀並發控制的核心機制。本文系統梳理鎖的七大模式、六大粒度、持有時間規則、自訂控制手段、死鎖處理與實戰範例,構建完整鎖知識體系。

一、為什麼需要鎖:四大並發異常

  • 遺失更新:兩用戶讀同一資料並修改,一修改覆蓋另一
  • 髒讀:讀到未提交的修改,後來回滾導致不一致
  • 不可重複讀:同一查詢前後兩次結果不一致(他人已修改提交)
  • 幻讀:同一範圍查詢前後筆數不同(他人插入/刪除)

二、七大鎖模式(資源鎖)

模式縮寫用途相容性關鍵點
共享鎖SSELECT 等唯讀操作多 S 相容;與 X/U 不相容
更新鎖U可更新資源預備階段單一 U,防止 S→X 轉換死鎖;修改時轉 X,否則轉 S
排他鎖XINSERT/UPDATE/DELETE獨佔,與所有其他鎖不相容
意圖鎖IS/IX/SIX建立鎖層級,表級標示意圖IS/IX/SIX 間相容性複雜,核心:防止表級 X 與頁/列級 S/X 衝突
結構描述鎖Sch-M/Sch-SDDL 操作 / 查詢編譯Sch-M 獨佔;Sch-S 與 Sch-M 互斥
大量更新鎖BUBULK INSERT + TABLOCK優化大量載入並發

意圖鎖細分

  • IS (Intent Shared):意圖在下層資源放 S 鎖(讀取部分)
  • IX (Intent Exclusive):意圖在下層放 X 鎖(修改部分),IS 的超集
  • SIX (Shared with Intent Exclusive):讀取全部 + 修改部分,表級 SIX + 頁級 IX + 列級 X,允許並發 IS

三、六大鎖粒度:粒度越細並發越高,開銷越大

資源描述
RID列識別碼,單列鎖定(堆疊表)
Key索引鍵鎖,保護可序列化交易鍵範圍
Page8KB 資料/索引頁
Extent8 頁連續組
Table整張表(含索引)
Database整個資料庫

四、鎖持有時間:隔離等級決定讀鎖壽命

  • READ COMMITTED (預設):讀取頁期間持有 S 鎖,掃描到下一頁釋放
  • HOLDLOCK / REPEATABLE READ / SERIALIZABLE:交易結束才釋放 S 鎖
  • 游標捲動鎖:下一次 FETCH 或關閉游標釋放;加 HOLDLOCK 則交易結束釋放
  • X 鎖:交易結束才釋放

五、自訂鎖控制五大手段

  1. 死鎖優先權: SET DEADLOCK_PRIORITY LOW/NORMAL/HIGH/@var,決定犧牲者
  2. 鎖逾時: SET LOCK_TIMEOUT 1800 (毫秒),逾時自動取消並回傳錯誤 1222;@@LOCK_TIMEOUT 查看當前設定
  3. 交易隔離等級: SET TRANSACTION ISOLATION LEVEL ...
  4. 表級鎖定提示: WITH (HOLDLOCK, ROWLOCK, TABLOCKX, UPDLOCK, NOLOCK, READPAST...)
  5. 索引鎖粒度配置: sp_indexoption 禁用頁/列鎖強制表鎖

六、查看鎖資訊

  • EXEC sp_lock 經典報表
  • 查詢分析器 Ctrl+2 快捷鍵
  • DMV:sys.dm_tran_locks、sys.dm_os_waiting_tasks 現代替代

七、死鎖避免六大原則

  1. 縮短交易邏輯,盡早提交/回滾
  2. 設定合理死鎖逾時(3-10 分鐘),避免進程懸掛
  3. 優化存取順序,統一多表操作順序
  4. 上線前嚴格測試所有腳本與預存程序
  5. 所有預存程序必須有 @error 錯誤處理
  6. 不輕易修改預設隔離等級,不建議強制加鎖提示

八、實戰範例:三大經典場景演示

1. 排他鎖阻塞讀取

-- 連線 1
BEGIN TRAN
UPDATE table1 SET A='aa' WHERE B='b2'
WAITFOR DELAY '00:00:30'
COMMIT TRAN

-- 連線 2 (同時執行)
BEGIN TRAN
SELECT * FROM table1 WHERE B='b2'
COMMIT TRAN
-- SELECT 必須等待 30 秒

2. 共享鎖允許並發讀,阻塞寫入

-- 連線 1
BEGIN TRAN
SELECT * FROM table1 WITH (HOLDLOCK) WHERE B='b2'
WAITFOR DELAY '00:00:30'
COMMIT TRAN

-- 連線 2
BEGIN TRAN
SELECT A,C FROM table1 WHERE B='b2'  -- 可立即執行
UPDATE table1 SET A='aa' WHERE B='b2' -- 必須等待 30 秒
COMMIT TRAN

3. 經典死鎖:資源請求順序相反

-- 連線 1: 先鎖 table1 再鎖 table2
-- 連線 2: 先鎖 table2 再鎖 table1
-- 系統偵測死鎖,選擇犧牲者中止

九、補充:應用程式鎖

  • 客戶端代碼生成,非引擎內部鎖
  • sp_getapplock 取得 / sp_releaseapplock 釋放
  • 適用:跨表/跨資料庫邏輯互斥、單例執行控制

十、表級鎖提示快速對照 (SQL 2000/2005/2008 通用)

提示效果等價隔離等級
HOLDLOCK持有 S 鎖至交易結束SERIALIZABLE
NOLOCK不發 S 鎖,允許髒讀READ UNCOMMITTED
ROWLOCK強制列鎖
TABLOCKX獨佔表鎖,阻塞所有存取
UPDLOCK讀取時取 U 鎖而非 S 鎖
READPAST跳過已鎖列 (僅 RID)

深度掌握鎖機制,是寫出高並發、低阻塞、無死鎖 SQL 程式碼的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved