數據庫-鎖的實踐

一:鎖的概念html

        按照寫技術博客的套路,應該對鎖的概念作一個介紹,我又想,能點擊進入本篇博客的同窗,想必都是據說過鎖的。因此我儘可能用簡練的語言來表述一下。數據庫

        鎖的定義:鎖主要用於多用戶環境下,保證數據庫完整性和一致性的技術。網絡

        鎖的解釋:當多個用戶併發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的狀況。若對併發操做不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的完整性和一致性。當事務在對某個數據對象進行操做前,先向系統發出請求,對其加鎖。加鎖後事務就對該數據對象有了必定的控制。併發

二:鎖的分類學習

        鎖的概念很是簡單,簡單的來用幾句話就能描述它的用途。可是鎖的分類,就明顯要複雜一些了。優化

        鎖的分類,在教材上,網絡上好多都是按兩個維度來描述的。一種維度是按鎖的功能來劃分,一種維度是按概念來劃分。09年的時候,我作了一個數據庫的培訓教程,把鎖的分類給截出來擺一下。spa

 

時隔了幾年,看起來PPT看起來很粗糙。與我這些PPT模板無法比,可是內容仍然經典。code

三:鎖的關鍵字htm

       共享鎖,排它鎖這樣的鎖,數據庫引擎會自動管理和優化,平時寫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 --此時是查不出結果的,會無限地等待下去,由於排它鎖未釋放,默認查詢的共享鎖與之不兼容,因此就一直等待排它鎖的釋放,纔會返回結果,即便表中已有許多數據,而排它鎖只鎖了一條記錄,可是,查詢語句也要等待這一條記錄的鎖的釋放,纔會返回結果。 這即是人工手動設置的由於排它鎖未釋放而致使的死鎖(不是相互等待,而是一方無盡的等待!)。

 

歡迎討論。

相關文章
相關標籤/搜索