一:鎖的概念
按照寫技術博客的套路,應該對鎖的概念做一個介紹,我又想,能點擊進入本篇博客的同學,想必都是聽說過鎖的。所以我盡量用簡練的語言來表述一下。
鎖的定義:鎖主要用于多用戶環境下,保證數據庫完整性和一致性的技術。
鎖的解釋:當多個用戶并發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的情況。若對并發操作不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的完整性和一致性。當事務在對某個數據對象進行操作前,先向系統發出請求,對其加鎖。加鎖后事務就對該數據對象有了一定的控制。
二:鎖的分類
鎖的概念非常簡單,簡單的來用幾句話就能描述它的用途。但是鎖的分類,就明顯要復雜一些了。
鎖的分類,在教材上,網絡上好多都是按兩個維度來描述的。一種維度是按鎖的功能來劃分,一種維度是按概念來劃分。09年的時候,我做了一個數據庫的培訓教程,把鎖的分類給截出來擺一下。
時隔了幾年,看起來PPT看起來很粗糙。與我這些PPT模板沒法比,但是內容仍然經典。
三:鎖的關鍵字
共享鎖,排它鎖這樣的鎖,數據庫引擎會自動管理和優化,平時寫SQL的時候,很少有去關心鎖的關鍵字。
但是今天是抱著學習的態度來看博客的,所以必須得把這幾個關鍵字都用一篇。
SELECT * FROM AppLog WITH (HOLDLOCK) /*共享鎖*/ SELECT * FROM AppLog WITH (UPDLOCK) /*更新鎖*/ SELECT * FROM AppLog WITH (XLOCK) WHERE LogID='AA599A4E-B727-4A65-8010-00001661765E'; /*排它鎖*/ SELECT * FROM AppLog WITH (ROWLOCK) WHERE LogID='6BE2C680-0C9F-43FA-9B4E-00000A6C1CEF'; /*行鎖*/ SELECT * FROM AppLog WITH (TABLOCKX) /*大容量更新鎖*/ SELECT * FROM AppLog WITH (XLOCK,ROWLOCK) WHERE LogID='AA599A4E-B727-4A65-8010-00001661765E'; /*鎖的組合使用*/ /*XLOCK 本身是鎖住數據行的,TABLOCKX是鎖住整張表*/ SELECT * FROM AppLog WITH (NOLOCK) /*不加鎖,當一個事務回滾后,出現臟數據*/ SELECT * FROM AppLog WITH (READPAST) /*忽略掉加鎖的數據(行數據,頁數據)*/
四:死鎖的發生
比如現在的數據庫用兩個用戶在用,
用戶1:
BEGIN TRAN SELECT * FROM AppLog WHERE LogID = 'A10BA165-6E52-4AFB-9EA8-000000D6B90A'; UPDATE AppLog SET AppPostion = AppPostion + AppPostion WHERE LogID = 'A10BA165-6E52-4AFB-9EA8-000000D6B90A';
用戶2:
BEGIN TRAN SELECT * FROM AppLog WHERE LogID = 'A10BA165-6E52-4AFB-9EA8-000000D6B90A'; UPDATE AppLog SET AppPostion = AppPostion + AppPostion WHERE LogID = 'A10BA165-6E52-4AFB-9EA8-000000D6B90A';
比如用戶1,用戶2同時執行 SELECT,用戶1對記錄加了共享鎖,用戶2對記錄也加了共享鎖,當用戶1 SELECT 執行完畢,準備執行UPDATE的時候,根據鎖機制,用戶1的共享鎖需要升
級到排他鎖才能執行接下來的UPDATE.
在升級排他鎖前,必須等待記錄上的其它共享鎖釋放,但是因為共享鎖只有等事務結束后才釋放。因為用戶2的共享鎖不釋放而導致用戶1等(等用戶2釋放共享鎖,自己好升級成排他鎖),同理,這時也因為用戶1的共享鎖不釋放而導致用戶2等待。死鎖就發生了。
五:無鎖查詢技巧
打開兩個查詢窗口:其中一個執行下面語句:
CREATE TABLE a ( id INT , name NVARCHAR(20) ) BEGIN TRAN INSERT a VALUES ('1','a')--開啟一個事務,而不提交也不回滾,此時insert 語句產生的排它鎖是不會釋放的
在另一個窗口中執行:
select COUNT(*) from a with(nolock)--無鎖查詢,會查出結果為1 select COUNT(*) from a with(readpast)--忽略所有有鎖的記錄,此時為0
然后執行select * from a --此時是查不出結果的,會無限地等待下去,因為排它鎖未釋放,默認查詢的共享鎖與之不兼容,所以就一直等待排它鎖的釋放,才會返回結果,即使表中已有許多數據,而排它鎖只鎖了一條記錄,但是,查詢語句也要等待這一條記錄的鎖的釋放,才會返回結果。 這便是人工手動設置的因為排它鎖未釋放而導致的死鎖(不是相互等待,而是一方無盡的等待!)。
歡迎討論。
文章列表