掌握SQLServer鎖的相關概念

一.爲何要引入鎖程序員

 

  當多個用戶同時對數據庫的併發操做時會帶來如下數據不一致的問題:sql

  ◆丟失更新數據庫

  A,B兩個用戶讀同一數據並進行修改,其中一個用戶的修改結果破壞了另外一個修改的結果,好比訂票系統安全

  ◆髒讀架構

  A用戶修改了數據,隨後B用戶又讀出該數據,但A用戶由於某些緣由取消了對數據的修改,數據恢復原值,此時B獲得的數據就與數據庫內的數據產生了不一致併發

  ◆不可重複讀oracle

  A用戶讀取數據,隨後B用戶讀出該數據並修改,此時A用戶再讀取數據時發現先後兩次的值不一致app

  併發控制的主要方法是封鎖,鎖就是在一段時間內禁止用戶作某些操做以免產生數據不一致sqlserver

  二鎖的分類post

  ◆鎖的類別有兩種分法:

  1.從數據庫系統的角度來看:分爲獨佔鎖(即排它鎖),共享鎖和更新鎖

  MS-SQLServer使用如下資源鎖模式。

  鎖模式描述

  共享(S)用於不更改或不更新數據的操做(只讀操做),如SELECT語句。

  更新(U)用於可更新的資源中。防止當多個會話在讀取、鎖定以及隨後可能進行的資源更新時發生常見形式的死鎖。

  排它(X)用於數據修改操做,例如INSERT、UPDATE或DELETE。確保不會同時同一資源進行多重更新。

  意向鎖用於創建鎖的層次結構。意向鎖的類型爲:意向共享(IS)、意向排它(IX)以及與意向排它共享(SIX)。

  架構鎖在執行依賴於表架構的操做時使用。架構鎖的類型爲:架構修改(Sch-M)和架構穩定性(Sch-S)。

  大容量更新(BU)向表中大容量複製數據並指定了TABLOCK提示時使用。

  ◆共享鎖

  共享(S)鎖容許併發事務讀取(SELECT)一個資源。資源上存在共享(S)鎖時,任何其它事務都不能修改數據。一旦已經讀取數據,便當即釋放資源上的共享(S)鎖,除非將事務隔離級別設置爲可重複讀或更高級別,或者在事務生存週期內用鎖定提示保留共享(S)鎖。

  ◆更新鎖

  更新(U)鎖能夠防止一般形式的死鎖。通常更新模式由一個事務組成,此事務讀取記錄,獲取資源(頁或行)的共享(S)鎖,而後修改行,此操做要求鎖轉換爲排它(X)鎖。若是兩個事務得到了資源上的共享模式鎖,而後試圖同時更新數據,則一個事務嘗試將鎖轉換爲排它(X)鎖。共享模式到排它鎖的轉換必須等待一段時間,由於一個事務的排它鎖與其它事務的共享模式鎖不兼容;發生鎖等待。第二個事務試圖獲取排它(X)鎖以進行更新。因爲兩個事務都要轉換爲排它(X)鎖,而且每一個事務都等待另外一個事務釋放共享模式鎖,所以發生死鎖。

  若要避免這種潛在的死鎖問題,請使用更新(U)鎖。一次只有一個事務能夠得到資源的更新(U)鎖。若是事務修改資源,則更新(U)鎖轉換爲排它(X)鎖。不然,鎖轉換爲共享鎖。

  ◆排它鎖

  排它(X)鎖能夠防止併發事務對資源進行訪問。其它事務不能讀取或修改排它(X)鎖鎖定的數據。

  意向鎖

  意向鎖表示SQLServer須要在層次結構中的某些底層資源上獲取共享(S)鎖或排它(X)鎖。例如,放置在表級的共享意向鎖表示事務打算在表中的頁或行上放置共享(S)鎖。在表級設置意向鎖可防止另外一個事務隨後在包含那一頁的表上獲取排它(X)鎖。意向鎖能夠提升性能,由於SQLServer僅在表級檢查意向鎖來肯定事務是否能夠安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以肯定事務是否能夠鎖定整個表。

  意向鎖包括意向共享(IS)、意向排它(IX)以及與意向排它共享(SIX)。

  鎖模式描述

  意向共享(IS)經過在各資源上放置S鎖,代表事務的意向是讀取層次結構中的部分(而不是所有)底層資源。

  意向排它(IX)經過在各資源上放置X鎖,代表事務的意向是修改層次結構中的部分(而不是所有)底層資源。IX是IS的超集。

  與意向排它共享(SIX)經過在各資源上放置IX鎖,代表事務的意向是讀取層次結構中的所有底層資源並修改部分(而不是所有)底層資源。容許頂層資源上的併發IS鎖。例如,表的SIX鎖在表上放置一個SIX鎖(容許併發IS鎖),在當前所修改頁上放置IX鎖(在已修改行上放置X鎖)。雖然每一個資源在一段時間內只能有一個SIX鎖,以防止其它事務對資源進行更新,可是其它事務能夠經過獲取表級的IS鎖來讀取層次結構中的底層資源。

  ◆獨佔鎖:

  只容許進行鎖定操做的程序使用,其餘任何對他的操做均不會被接受。執行數據更新命令時,SQLServer會自動使用獨佔鎖。當對象上有其餘鎖存在時,沒法對其加獨佔鎖。

  共享鎖:共享鎖鎖定的資源能夠被其餘用戶讀取,但其餘用戶沒法修改它,在執行Select時,SQLServer會對對象加共享鎖。

  ◆更新鎖:

  當SQLServer準備更新數據時,它首先對數據對象做更新鎖鎖定,這樣數據將不能被修改,但能夠讀取。等到SQLServer肯定要進行更新數據操做時,他會自動將更新鎖換爲獨佔鎖,當對象上有其餘鎖存在時,沒法對其加更新鎖。

  2.從程序員的角度看:分爲樂觀鎖和悲觀鎖。

  樂觀鎖:徹底依靠數據庫來管理鎖的工做。

  悲觀鎖:程序員本身管理數據或對象上的鎖處理。

  MS-SQLSERVER使用鎖在多個同時在數據庫內執行修改的用戶間實現悲觀併發控制

  三鎖的粒度

  鎖粒度是被封鎖目標的大小,封鎖粒度小則併發性高,但開銷大,封鎖粒度大則併發性低但開銷小

  SQLServer支持的鎖粒度能夠分爲爲行、頁、鍵、鍵範圍、索引、表或數據庫獲取鎖

  資源描述

  RID行標識符。用於單獨鎖定表中的一行。

  鍵索引中的行鎖。用於保護可串行事務中的鍵範圍。

  頁8千字節(KB)的數據頁或索引頁。

  擴展盤區相鄰的八個數據頁或索引頁構成的一組。

  表包括全部數據和索引在內的整個表。

  DB數據庫。

  四鎖定時間的長短

  鎖保持的時間長度爲保護所請求級別上的資源所需的時間長度。

  用於保護讀取操做的共享鎖的保持時間取決於事務隔離級別。採用READCOMMITTED的默認事務隔離級別時,只在讀取頁的期間內控制共享鎖。在掃描中,直到在掃描內的下一頁上獲取鎖時才釋放鎖。若是指定HOLDLOCK提示或者將事務隔離級別設置爲REPEATABLEREAD或SERIALIZABLE,則直到事務結束才釋放鎖。

  根據爲遊標設置的併發選項,遊標能夠獲取共享模式的滾動鎖以保護提取。當須要滾動鎖時,直到下一次提取或關閉遊標(以先發生者爲準)時才釋放滾動鎖。可是,若是指定HOLDLOCK,則直到事務結束才釋放滾動鎖。

  用於保護更新的排它鎖將直到事務結束才釋放。

  若是一個鏈接試圖獲取一個鎖,而該鎖與另外一個鏈接所控制的鎖衝突,則試圖獲取鎖的鏈接將一直阻塞到:

  將衝突鎖釋放並且鏈接獲取了所請求的鎖。

  鏈接的超時間隔已到期。默認狀況下沒有超時間隔,可是一些應用程序設置超時間隔以防止無限期等待

  五SQLServer中鎖的自定義

  ◆處理死鎖和設置死鎖優先級

  死鎖就是多個用戶申請不一樣封鎖,因爲申請者均擁有一部分封鎖權而又等待其餘用戶擁有的部分封鎖而引發的無休止的等待

  可使用SETDEADLOCK_PRIORITY控制在發生死鎖狀況時會話的反應方式。若是兩個進程都鎖定數據,而且直到其它進程釋放本身的鎖時,每一個進程才能釋放本身的鎖,即發生死鎖狀況。

  ◆2處理超時和設置鎖超時持續時間。

  @@LOCK_TIMEOUT返回當前會話的當前鎖超時設置,單位爲毫秒

  SETLOCK_TIMEOUT設置容許應用程序設置語句等待阻塞資源的最長時間。當語句等待的時間大於LOCK_TIMEOUT設置時,系統將自動取消阻塞的語句,並給應用程序返回"已超過了鎖請求超時時段"的1222號錯誤信息

  示例

  下例將鎖超時期限設置爲1,800毫秒。

  SETLOCK_TIMEOUT1800

  ◆設置事務隔離級別。

  ◆對SELECT、INSERT、UPDATE和DELETE語句使用表級鎖定提示。

  ◆配置索引的鎖定粒度

  可使用sp_indexoption系統存儲過程來設置用於索引的鎖定粒度

  六查看鎖的信息

  1執行EXECSP_LOCK報告有關鎖的信息

  2查詢分析器中按Ctrl+2能夠看到鎖的信息

  七使用注意事項

  如何避免死鎖

  1使用事務時,儘可能縮短事務的邏輯處理過程,及早提交或回滾事務;

  2設置死鎖超時參數爲合理範圍,如:3分鐘-10分種;超過期間,自動放棄本次操做,避免進程懸掛;

  3優化程序,檢查並避免死鎖現象出現;

  4.對全部的腳本和SP都要仔細測試,在正是版本以前。

  5全部的SP都要有錯誤處理(經過@error)

  6通常不要修改SQLSERVER事務的默認級別。不推薦強行加鎖

  解決問題如何對行表數據庫加鎖

  八幾個有關鎖的問題

  1如何鎖一個表的某一行

  SETTRANSACTIONISOLATIONLEVELREADUNCOMMITTED

  SELECT*FROMtableROWLOCKWHEREid=1

  2鎖定數據庫的一個表

  SELECT*FROMtableWITH(HOLDLOCK)

  加鎖語句:

  sybase:

  update表setcol1=col1where1=0;

  MSSQL:

  selectcol1from表(tablockx)where1=0;

  oracle:

  LOCKTABLE表INEXCLUSIVEMODE;

  加鎖後其它人不可操做,直到加鎖用戶解鎖,用commit或rollback解鎖

  幾個例子幫助你們加深印象

  設table1(A,B,C)

  ABC

  a1b1c1

  a2b2c2

  a3b3c3

  ◆排它鎖

  新建兩個鏈接

  在第一個鏈接中執行如下語句

  begintran

  updatetable1

  setA=''aa''

  whereB=''b2''

  waitfordelay''00:00:30''--等待30秒

  committran

  在第二個鏈接中執行如下語句

  begintran

  select*fromtable1

  whereB=''b2''

  committran

  若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒

  ◆共享鎖

  在第一個鏈接中執行如下語句

  begintran

  select*fromtable1holdlock-holdlock人爲加鎖

  whereB=''b2''

  waitfordelay''00:00:30''--等待30秒

  committran

  ◆共享鎖

  在第一個鏈接中執行如下語句

  begintran

  select*fromtable1holdlock-holdlock人爲加鎖

  whereB=''b2''

  waitfordelay''00:00:30''--等待30秒

  committran

  在第二個鏈接中執行如下語句

  begintran

  selectA,Cfromtable1

  whereB=''b2''

  updatetable1

  setA=''aa''

  whereB=''b2''

  committran

  若同時執行上述兩個語句,則第二個鏈接中的select查詢能夠執行

  而update必須等待第一個事務釋放共享鎖轉爲排它鎖後才能執行即要等待30秒

  ◆死鎖

  增設table2(D,E)

  DE

  d1e1

  d2e2

  在第一個鏈接中執行如下語句

  begintran

  updatetable1

  setA=''aa''

  whereB=''b2''

  waitfordelay''00:00:30''

  updatetable2

  setD=''d5''

  whereE=''e1''

  committran

  在第二個鏈接中執行如下語句

  begintran

  updatetable2

  setD=''d5''

  whereE=''e1''

  waitfordelay''00:00:10''

  updatetable1

  setA=''aa''

  whereB=''b2''

  committran

  同時執行,系統會檢測出死鎖,並停止進程

  補充一點:

  SQLServer2000支持的表級鎖定提示

  HOLDLOCK持有共享鎖,直到整個事務完成,應該在被鎖對象不須要時當即釋放,等於SERIALIZABLE事務隔離級別

  NOLOCK語句執行時不發出共享鎖,容許髒讀,等於READUNCOMMITTED事務隔離級別

  PAGLOCK在使用一個表鎖的地方用多個頁鎖

  READPAST讓SQLServer跳過任何鎖定行,執行事務,適用於READUNCOMMITTED事務隔離級別只跳過RID鎖,不跳過頁,區域和表鎖

  ROWLOCK強制使用行鎖

  TABLOCKX強制使用獨佔表級鎖,這個鎖在事務期間阻止任何其餘事務使用這個表

  UPLOCK強制在讀表時使用更新而不用共享鎖

  應用程序鎖:

  應用程序鎖就是客戶端代碼生成的鎖,而不是sqlserver自己生成的鎖

  處理應用程序鎖的兩個過程

  sp_getapplock鎖定應用程序資源

  sp_releaseapplock爲應用程序資源解鎖

  注意:鎖定數據庫的一個表的區別

  SELECT*FROMtableWITH(HOLDLOCK)其餘事務能夠讀取表,但不能更新刪除

  SELECT*FROMtableWITH(TABLOCKX)其餘事務不能讀取表,更新和刪除

相關文章
相關標籤/搜索