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

SQL Server 2000 並發控制完整指南:鎖定、隔離等級與阻塞解決方案

     編輯:關於SqlServer

並發問題的四大類型

問題說明發生情境
遺失更新兩筆交易讀取同一資料,後寫入者覆蓋先寫入者的修改無鎖定、最後寫入勝出
髒讀讀取到其他交易未提交的修改資料隔離等級 Read Uncommitted
不可重複讀同一交易多次讀取同一資料,結果不一致 (他人已提交修改)隔離等級 Read Committed
幻讀同一交易多次範圍查詢,結果筆數不同 (他人插入/刪除)隔離等級 Repeatable Read

SQL-92 四大隔離等級對照表

隔離等級髒讀不可重複讀幻讀並發度備註
Read Uncommitted✅ 發生✅ 發生✅ 發生最高NOLOCK 提示等效
Read Committed (預設)❌ 防止✅ 發生✅ 發生高共享鎖讀取後立即釋放
Repeatable Read❌ 防止❌ 防止✅ 發生中共享鎖持有至交易結束
Serializable❌ 防止❌ 防止❌ 防止最低範圍鎖 (Key-Range Lock)

設定交易隔離等級

1. 連接層級 (SESSION) - SET TRANSACTION ISOLATION LEVEL

-- 設定目前連接的預設隔離等級
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 驗證目前設定
DBCC USEROPTIONS;
-- 結果中 isolation level = repeatable read

選項:READ COMMITTED | READ UNCOMMITTED | REPEATABLE READ | SERIALIZABLE

2. 陳述式層級 - 資料表提示 (Table Hints)

-- 僅影響此查詢,不影響連接其他陳述式
SELECT * FROM Authors WITH (NOLOCK);           -- Read Uncommitted
SELECT * FROM Authors WITH (HOLDLOCK);         -- Serializable (等同 SERIALIZABLE)
SELECT * FROM Authors WITH (READPAST);         -- 跳過已鎖定列
SELECT * FROM Authors WITH (UPDLOCK, HOLDLOCK);-- 更新鎖 + 持有至交易結束

建議:僅在必要時使用表提示,優先調整連接層級隔離等級。

3. 應用程式層級 (API)

API設定方式
ADOConnection.IsolationLevel = adXactReadCommitted / adXactRepeatableRead / adXactReadSerializable
OLE DBITransactionLocal::StartTransaction (isoLevel = ISOLATIONLEVEL_READCOMMITTED...)
ODBCSQLSetConnectAttr (SQL_ATTR_TXN_ISOLATION, SQL_TXN_READ_COMMITTED...)

遺失更新的特殊處理

隔離等級 Repeatable Read 或 Serializable 可防止遺失更新。但若兩交易使用單一 UPDATE 陳述式 (不依賴先前讀取值),預設 Read Committed 即可避免遺失更新,因更新鎖 (U/X Lock) 會序列化寫入。

實務阻塞排查與解決

1. 即時監控阻塞鏈

-- sp_who2 替代版:顯示阻塞鏈、等待資源、執行 SQL
SELECT 
    r.session_id AS SPID,
    r.blocking_session_id AS BlockerSPID,
    r.wait_type,
    r.wait_time_ms,
    r.wait_resource,
    st.text AS SQLText,
    DB_NAME(r.database_id) AS DBName
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st
WHERE r.blocking_session_id > 0 OR r.session_id IN (
    SELECT blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id > 0
);

2. 關鍵等待類型對照

  • LCK_M_S:等待共享鎖 (SELECT 被 UPDATE 阻塞)
  • LCK_M_X:等待獨佔鎖 (UPDATE/DELETE 被其他寫入阻塞)
  • LCK_M_U:等待更新鎖
  • PAGEIOLATCH_*:I/O 瓶頸非鎖定問題

3. 死鎖 (Deadlock) 處理

  • 啟用追蹤旗標 1204 / 1222 記錄死鎖圖至錯誤日誌。
  • 使用 擴充事件 (Extended Events) 捕捉 xml_deadlock_report (SQL 2008+)。
  • 應用層實作重試邏輯 (捕捉錯誤 1205),指數退避重試。

4. 長交易最佳實務

  • 縮短交易範圍:盡早 COMMIT/ROLLBACK。
  • 避免交易中進行使用者互動、遠端呼叫、大量運算。
  • 大量異動分批處理 (Batch),每批獨立交易。
  • 設定 SET LOCK_TIMEOUT 5000 避免無限等待 (單位:毫秒)。

進階:快照隔離 (Snapshot Isolation) - SQL 2005+

啟用資料庫選項 ALLOW_SNAPSHOT_ISOLATION 與 READ_COMMITTED_SNAPSHOT,以版本儲存 (row versioning in tempdb) 實現「讀不阻寫、寫不阻讀」,大幅提升高並發系統吞吐量。代價:tempdb 壓力增加、更新衝突需應用層處理 (錯誤 3960)。

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