鎖是網絡數據庫中的一個非常重要的概念
它主要用於多用戶環境下保證數據庫完整性和一致性
各種大型數據庫所采用的鎖的基本理論是一致的
但在具體實現上各有差別
目前
大多數數據庫管理系統都或多或少具有自我調節
自我管理的功能
因此很多用戶實際上不清楚鎖的理論和所用數據庫中鎖的具體實現
Microsoft SQL Server(以下簡稱SQL Server)作為一種中小型數據庫管理系統
已經得到了廣泛的應用
該系統更強調由系統來管理鎖
在用戶有SQL請求時
系統分析請求
自動在滿足鎖定條件和系統性能之間為數據庫加上適當的鎖
同時系統在運行期間常常自動進行優化處理
實行動態加鎖
對於一般的用戶而言
通過系統的自動鎖定管理機制基本可以滿足使用要求
但如果對數據安全
數據庫完整性和一致性有特殊要求
就必須自己控制數據庫的鎖定和解鎖
這就需要了解SQL Server的鎖機制
掌握數據庫鎖定方法
鎖的多粒度性以及鎖升級
數據庫中的鎖是指一種軟件機制
用來指示某個用戶(也即進程會話
下同)已經占用了某種資源
從而防止其他用戶做出影響本用戶的數據修改或導致數據庫數據的非完整性和非一致性
這兒所謂資源
主要指用戶可以操作的數據行
索引以及數據表等
根據資源的不同
鎖有多粒度(multigranular)的概念
也就是指可以鎖定的資源的層次
SQL Server中能夠鎖定的資源粒度包括
數據庫
表
區域
頁面
鍵值(指帶有索引的行數據)
行標識符(RID
即表中的單行數據)
采用多粒度鎖的重要用途是用來支持並發操作和保證數據的完整性
SQL Server根據用戶的請求
做出分析後自動給數據庫加上合適的鎖
假設某用戶只操作一個表中的部分行數據
系統可能會只添加幾個行鎖(RID)或頁面鎖
這樣可以盡可能多地支持多用戶的並發操作
但是
如果用戶事務中頻繁對某個表中的多條記錄操作
將導致對該表的許多記錄行都加上了行級鎖
數據庫系統中鎖的數目會急劇增加
這樣就加重了系統負荷
影響系統性能
因此
在數據庫系統中
一般都支持鎖升級(lock escalation)
所謂鎖升級是指調整鎖的粒度
將多個低粒度的鎖替換成少數的更高粒度的鎖
以此來降低系統負荷
在SQL Server中當一個事務中的鎖較多
達到鎖升級門限時
系統自動將行級鎖和頁面鎖升級為表級鎖
特別值得注意的是
在SQL Server中
鎖的升級門限以及鎖升級是由系統自動來確定的
不需要用戶設置
鎖的模式和兼容性
在數據庫中加鎖時
除了可以對不同的資源加鎖
還可以使用不同程度的加鎖方式
即鎖有多種模式
SQL Server中鎖模式包括
.共享鎖
SQL Server中
共享鎖用於所有的只讀數據操作
共享鎖是非獨占的
允許多個並發事務讀取其鎖定的資源
默認情況下
數據被讀取後
SQL Server立即釋放共享鎖
例如
執行查詢
SELECT * FROM my_table
時
首先鎖定第一頁
讀取之後
釋放對第一頁的鎖定
然後鎖定第二頁
這樣
就允許在讀操作過程中
修改未被鎖定的第一頁
但是
事務隔離級別連接選項設置和SELECT語句中的鎖定設置都可以改變SQL Server的這種默認設置
例如
SELECT * FROM my_table HOLDLOCK
就要求在整個查詢過程中
保持對表的鎖定
直到查詢完成才釋放鎖定
.修改鎖
修改鎖在修改操作的初始化階段用來鎖定可能要被修改的資源
這樣可以避免使用共享鎖造成的死鎖現象
因為使用共享鎖時
修改數據的操作分為兩步
首先獲得一個共享鎖
讀取數據
然後將共享鎖升級為獨占鎖
然後再執行修改操作
這樣如果同時有兩個或多個事務同時對一個事務申請了共享鎖
在修改數據的時候
這些事務都要將共享鎖升級為獨占鎖
這時
這些事務都不會釋放共享鎖而是一直等待對方釋放
這樣就造成了死鎖
如果一個數據在修改前直接申請修改鎖
在數據修改的時候再升級為獨占鎖
就可以避免死鎖
修改鎖與共享鎖是兼容的
也就是說一個資源用共享鎖鎖定後
允許再用修改鎖鎖定
.獨占鎖
獨占鎖是為修改數據而保留的
它所鎖定的資源
其他事務不能讀取也不能修改
獨占鎖不能和其他鎖兼容
.結構鎖
結構鎖分為結構修改鎖(Sch
M)和結構穩定鎖(Sch
S)
執行表定義語言操作時
SQL Server采用Sch
M鎖
編譯查詢時
SQL Server采用Sch
S鎖
.意向鎖
意向鎖說明SQL Server有在資源的低層獲得共享鎖或獨占鎖的意向
例如
表級的共享意向鎖說明事務意圖將獨占鎖釋放到表中的頁或者行
意向鎖又可以分為共享意向鎖
獨占意向鎖和共享式獨占意向鎖
共享意向鎖說明事務意圖在共享意向鎖所鎖定的低層資源上放置共享鎖來讀取數據
獨占意向鎖說明事務意圖在共享意向鎖所鎖定的低層資源上放置獨占鎖來修改數據
共享式獨占鎖說明事務允許其他事務使用共享鎖來讀取頂層資源
並意圖在該資源低層上放置獨占鎖
.批量修改鎖
批量復制數據時使用批量修改鎖
可以通過表的TabLock提示或者使用系統存儲過程sp_tableoption的
table lock on bulk load
選項設定批量修改鎖
另外
SQL Server命令語句操作會影響鎖定的方式
語句的組合也同樣能產生不同的鎖定
詳情如下表
鎖沖突及其防止辦法
在數據庫系統中
死鎖是指多個用戶(進程)分別鎖定了一個資源
並又試圖請求鎖定對方已經鎖定的資源
這就產生了一個鎖定請求環
導致多個用戶(進程)都處於等待對方釋放所鎖定資源的狀態
在SQL Server中
系統能夠自動定期搜索和處理死鎖問題
系統在每次搜索中標識所有等待鎖定請求的進程會話
如果在下一次搜索中該被標識的進程仍處於等待狀態
SQL Server就開始遞歸死鎖搜索
當搜索檢測到鎖定請求環時
系統將根據各進程會話的死鎖優先級別來結束一個優先級最低的事務
此後
系統回滾該事務
並向該進程發出
號錯誤信息
這樣
其他事務就有可能繼續運行了
死鎖優先級的設置語句為
SET DEADLOCK_PRIORITY { LOW | NORMAL}
其中LOW說明該進程會話的優先級較低
在出現死鎖時
可以首先中斷該進程的事務
另外
各進程中通過設置LOCK_TIMEOUT選項能夠設置進程處於鎖定請求狀態的最長等待時間
該設置的語句
SET LOCK_TIMEOUT { timeout_period }
其中
timeout_period以毫秒為單位
理解了死鎖的概念
在應用程序中就可以采用下面的一些方法來盡量避免死鎖了
(
)合理安排表訪問順序
(
)在事務中盡量避免用戶干預
盡量使一個事務處理的任務少些
(
)采用髒讀技術
髒讀由於不對被訪問的表加鎖
而避免了鎖沖突
在客戶機/服務器應用環境中
有些事務往往不允許讀髒數據
但在特定的條件下
我們可以用髒讀
(
)數據訪問時域離散法
數據訪問時域離散法是指在客戶機/服務器結構中
采取各種控制手段控制對數據庫或數據庫中的對象訪問時間段
主要通過以下方式實現: 合理安排後台事務的執行時間
采用工作流對後台事務進行統一管理
工作流在管理任務時
一方面限制同一類任務的線程數(往往限制為
個)
防止資源過多占用; 另一方面合理安排不同任務執行時序
時間
盡量避免多個後台任務同時執行
另外
避免在前台交易高峰時間運行後台任務
(
)數據存儲空間離散法
數據存儲空間離散法是指采取各種手段
將邏輯上在一個表中的數據分散到若干離散的空間上去
以便改善對表的訪問性能
主要通過以下方法實現: 第一
將大表按行或列分解為若干小表; 第二
按不同的用戶群分解
(
)使用盡可能低的隔離性級別
隔離性級別是指為保證數據庫數據的完整性和一致性而使多用戶事務隔離的程度
SQL
定義了
種隔離性級別
未提交讀
提交讀
可重復讀和可串行
如果選擇過高的隔離性級別
如可串行
雖然系統可以因實現更好隔離性而更大程度上保證數據的完整性和一致性
但各事務間沖突而死鎖的機會大大增加
大大影響了系統性能
(
)使用Bound Connections
Bound connections 允許兩個或多個事務連接共享事務和鎖
而且任何一個事務連接要申請鎖如同另外一個事務要申請鎖一樣
因此可以允許這些事務共享數據而不會有加鎖的沖突
(
)考慮使用樂觀鎖定或使事務首先獲得一個獨占鎖定
一個最常見的死鎖情況發生在系列號生成器中
它們通常是這樣編寫的
begin tran
select new_id from keytab holdlock
update keytab set new_id=new_id+l
commit tran
如果有兩個用戶在同時運行這一事務
他們都會得到共享鎖定並保持它
當兩個用戶都試圖得到keytab表的獨占鎖定時
就會進入死鎖
為了避免這種情況的發生
應將上述事務重寫成如下形式
begin tran
update keytab set new_id=new_id+l
select new_id from keytab
commit tran
以這種方式改寫後
只有一個事務能得到keytab的獨占鎖定
其他進程必須等到第一個事務的完成
這樣雖增加了執行時間
但避免了死鎖
如果要求在一個事務中具有讀取的可重復能力
就要考慮以這種方式來編寫事務
以獲得資源的獨占鎖定
然後再去讀數據
例如
如果一個事務需要檢索出titles表中所有書的平均價格
並保證在update被應用前
結果不會改變
優化器就會分配一個獨占的表鎖定
考慮如下的SQL代碼
From:http://tw.wingwit.com/Article/program/SQLServer/201311/22085.html