轉自高手關於SQL 鎖的敘述。。(nolock,rowlock,tablock,xlock,paglock)

鎖的概述

一. 爲何要引入鎖

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

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

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

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

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

二 鎖的分類

鎖的類別有兩種分法:

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

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

鎖模式 描述
共享 (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) 鎖鎖定的數據。

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

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

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

獨佔鎖:只容許進行鎖定操做的程序使用,其餘任何對他的操做均不會被接受。執行數據更新命令時,SQL Server會自動使用獨佔鎖。當對象上有其餘鎖存在時,沒法對其加獨佔鎖。
共享鎖:共享鎖鎖定的資源能夠被其餘用戶讀取,但其餘用戶沒法修改它,在執行Select時,SQL Server會對對象加共享鎖。
更新鎖:當SQL Server準備更新數據時,它首先對數據對象做更新鎖鎖定,這樣數據將不能被修改,但能夠讀取。等到SQL Server肯定要進行更新數據操做時,他會自動將更新鎖換爲獨佔鎖,當對象上有其餘鎖存在時,沒法對其加更新鎖。

2. 從程序員的角度看:分爲樂觀鎖和悲觀鎖。
樂觀鎖:徹底依靠數據庫來管理鎖的工做。
悲觀鎖:程序員本身管理數據或對象上的鎖處理。

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

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

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

資源 描述
RID 行標識符。用於單獨鎖定表中的一行。
鍵 索引中的行鎖。用於保護可串行事務中的鍵範圍。
頁 8 千字節 (KB) 的數據頁或索引頁。
擴展盤區 相鄰的八個數據頁或索引頁構成的一組。
表 包括全部數據和索引在內的整個表。
DB 數據庫。

四 鎖定時間的長短

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

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

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

用於保護更新的排它鎖將直到事務結束才釋放。
若是一個鏈接試圖獲取一個鎖,而該鎖與另外一個鏈接所控制的鎖衝突,則試圖獲取鎖的鏈接將一直阻塞到:

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

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

五 SQL Server 中鎖的自定義

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

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

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

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

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

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

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

3) 設置事務隔離級別。

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

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

六 查看鎖的信息

1 執行 EXEC SP_LOCK 報告有關鎖的信息
2 查詢分析器中按Ctrl+2能夠看到鎖的信息

七 使用注意事項

如何避免死鎖
1 使用事務時,儘可能縮短事務的邏輯處理過程,及早提交或回滾事務;
2 設置死鎖超時參數爲合理範圍,如:3分鐘-10分種;超過期間,自動放棄本次操做,避免進程懸掛;
3 優化程序,檢查並避免死鎖現象出現;
4 .對全部的腳本和SP都要仔細測試,在正是版本以前。
5 全部的SP都要有錯誤處理(經過@error)
6 通常不要修改SQL SERVER事務的默認級別。不推薦強行加鎖

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

八 幾個有關鎖的問題

1 如何鎖一個表的某一行

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT * FROM table ROWLOCK WHERE id = 1

2 鎖定數據庫的一個表

SELECT * FROM table WITH (HOLDLOCK)

加鎖語句:
sybase:
update 表 set col1=col1 where 1=0 ;
MSSQL:
select col1 from 表 (tablockx) where 1=0 ;
oracle:
LOCK TABLE 表 IN EXCLUSIVE MODE ;
加鎖後其它人不可操做,直到加鎖用戶解鎖,用commit或rollback解鎖


幾個例子幫助你們加深印象
設table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3

1)排它鎖
新建兩個鏈接
在第一個鏈接中執行如下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二個鏈接中執行如下語句
begin tran
select * from table1
where B='b2'
commit tran

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

2)共享鎖
在第一個鏈接中執行如下語句
begin tran
select * from table1 holdlock -holdlock人爲加鎖
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran

在第二個鏈接中執行如下語句
begin tran
select A,C from table1
where B='b2'
update table1
set A='aa'
where B='b2'
commit tran

若同時執行上述兩個語句,則第二個鏈接中的select查詢能夠執行
而update必須等待第一個事務釋放共享鎖轉爲排它鎖後才能執行 即要等待30秒

3)死鎖
增設table2(D,E)
D E
d1 e1
d2 e2
在第一個鏈接中執行如下語句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30'
update table2
set D='d5'
where E='e1'
commit tran

在第二個鏈接中執行如下語句
begin tran
update table2
set D='d5'
where E='e1'
waitfor delay '00:00:10'
update table1
set A='aa'
where B='b2'
commit tran

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

補充一點:
Sql Server2000支持的表級鎖定提示

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

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

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

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

ROWLOCK 強制使用行鎖

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

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

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

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

sp_getapplock 鎖定應用程序資源

sp_releaseapplock 爲應用程序資源解鎖

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

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

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




SQL code
1 如何鎖一個表的某一行

A 鏈接中執行

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

begin tran

select * from tablename with (rowlock) where id=3

waitfor delay '00:00:05'

commit tran

B鏈接中若是執行

update tablename set colname='10' where id=3 --則要等待5秒

update tablename set colname='10' where id<>3 --可當即執行

2 鎖定數據庫的一個表

SELECT * FROM table WITH (HOLDLOCK)


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

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

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

------------------------------------------------------------------------------

 數據庫加鎖的知識收藏
關於數據庫加鎖的知識
LockType 屬性

指示編輯過程當中對記錄使用的鎖定類型。

設置和返回值

設置或返回如下某個 LockTypeEnum 的值。

常量 說明
adLockReadOnly 默認值,只讀。沒法更改數據。
adLockPessimistic 保守式記錄鎖定(逐條)。提供者執行必要的操做確保成功編輯記錄,一般採用編輯時當即鎖定數據源的記錄的方式。
adLockOptimistic 開放式記錄鎖定(逐條)。提供者使用開放式鎖定,只在調用 Update 方法時鎖定記錄。
adLockBatchOptimistic 開放式批更新。用於與當即更新模式相反的批更新模式。

說明
打開 Recordset 前設置 LockType 屬性可指定打開時提供者應該使用的鎖定類型。讀取該屬性可返回在打開的 Recordset 對象上正在使用的鎖定類型。Recordset 關閉時 LockType 屬性爲讀/寫,打開時該屬性爲只讀。

提供者可能不支持全部的鎖定類型。若是某提供者不支持所需的 LockType 設置,則將替換爲其餘類型的鎖定。要肯定 Recordset 對象可用的實際鎖定功能,請經過 adUpdate 和 adUpdateBatch 使用 Supports 方法。

若是 CursorLocation 屬性被設置爲 adUseClient,將不支持 adLockPessimistic 設置。設置不支持的值不會產生錯誤,由於此時將使用支持的最接近的 LockType 的值。

遠程數據服務用法 當在客戶端 (ADOR) 的 Recordset 對象上使用時,LockType 屬性只能設置爲 adLockOptimisticBatch。

------------------------------------------------------------------------------------
/********** 加鎖 ***************
設table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3

1)排它鎖
新建兩個鏈接
在第一個鏈接中執行如下語句
begin tran
   update table1
   set A=’aa’
   where B=’b2’
   waitfor delay ’00:00:30’ --等待30秒
commit tran
在第二個鏈接中執行如下語句
begin tran
   select * from table1
   where B=’b2’
commit tran

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

2)共享鎖
在第一個鏈接中執行如下語句
begin tran
   select * from table1 holdlock -holdlock人爲加鎖
   where B=’b2’
   waitfor delay ’00:00:30’ --等待30秒
commit tran

在第二個鏈接中執行如下語句
begin tran
   select A,C from table1
   where B=’b2’
   update table1
   set A=’aa’
   where B=’b2’
commit tran

若同時執行上述兩個語句,則第二個鏈接中的select查詢能夠執行
而update必須等待第一個鏈接中的共享鎖結束後才能執行 即要等待30秒

3)死鎖
增設table2(D,E)
D E
d1 e1
d2 e2
在第一個鏈接中執行如下語句
begin tran
   update table1
   set A=’aa’
   where B=’b2’
   waitfor delay ’00:00:30’
   update table2
   set D=’d5’
   where E=’e1’
commit tran

在第二個鏈接中執行如下語句
begin tran
   update table2
   set D=’d5’
   where E=’e1’
   waitfor delay ’00:00:10’
   update table1
   set A=’aa’
   where B=’b2’
commit tran

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

SET IMPLICIT_TRANSACTIONS ON --用戶每次必須顯式提交或回滾。不然當用戶斷開鏈接時,
                              --事務及其所包含的全部數據更改將回滾

SET IMPLICIT_TRANSACTIONS OFF --自動提交模式。在自動提交模式下,若是各個語句成功
                               --完成則提交。
--------------------------------------------------------------------------------------

修改前
RS.lock
完成後
RS.unlock
--------------------------------------------------------------------------------------


Sql中游標和加鎖的問題

日期:2000-11-27 15:42:00
出處:ALL ASP
做者:feny

<%
’遊標類型
Const adOpenForwardOnly = 0
Const adOpenKeyset = 1
Const adOpenDynamic = 2
Const adOpenStatic = 3

’加鎖類型
Const adLockReadOnly = 1
Const adLockPessimistic = 2
Const adLockOptimistic = 3
Const adLockBatchOptimistic = 4
>%

<% set conn = server.createobject(’adodb.connection’) >%
<% set rsmov = server.createobject(’adodb.recordset’) >%
<% conn.open ’數據源名稱’, ’sa’, ’ >%
<% rsmov.open sqlmov, conn, adopenkeyset, adlockreadonly >%

    遊標使用時是比較靈活的,它有時用來描述一個記錄集,有時又是用來描述當前記錄集中某一條記錄的指針。遊標主要是用來創建一個關係數據庫中行/列關係的一種SQL可利用的訪問格式。與遊標有關係的技術術語還有一個叫Bookmark的。若是你選擇的遊標方式支持Bookmarks。數據庫將提供有關記錄數目的強大功能。
    在上面寫出的那麼多遊標方式中,adOpenDynamic是沒有太的用處的,雖然它提供實時顯示數據庫中的記錄的全部更新操做的功能,可是由於並非全部的數據庫都支持該遊標方式,沒有移植性的遊標方式對當前錯綜複雜的數據庫來講真是用處不大。
    在實際的編程中,我相信你們使用得最頻繁的是adOpenStatic方式,固然這種方式的缺點是不可以就、實時反應出數據庫中內容改變時的情況。若是要想看到數據庫被其它用戶改變的情況,可以使用adOpenKeyse方式(可是它只可以反應出被編輯的改變狀況,也就是說不可以反映出新增和刪除記錄的改變狀況。)
    其實上面的內容你們通常均可以在微軟的技術參考資料中找到,下面來講說在使用這些遊標方式和加鎖方式時要注意到的問題。
    首先要注意到的是這兩種方式在混合使用時的問題,就是說你同時設置遊標方式和加鎖方式。除非你是在使用Access數據庫,通常而言當你混合使用時是並不可以獲得你預期想要的遊標方式和加鎖方式的。例如,若是你同時將遊標設置爲adOpenStatic方式,而將加鎖設置爲adLockOptimistic,你將得不到adOpenStatic方式的遊標,你這時使用的遊標方式將是adOpenKeyset,也就是說你使用ADO的話,它將返回adOpenKeyset的遊標。
    其次,遊標和加鎖的混合使用還會致使ADO返回的不是你想要的加鎖方式,ADO會改變你的加鎖方式。例如,在默認狀態下游標方式是adOpenForwardOnly,在使用這種遊標方式的同時若是你使用的加鎖方式爲-1(就是讓數據源來判斷加鎖方式)或則adLockReadOnly,那麼這種混合方式基本上不支持RecordSet的任何方法,也就是說RecordSet的任何方法將返回False(你的recordcount,absoultpage,addnew,delete,update等都會返回-1,-1就是表示不支持該屬性),可是這時若是你使用的是adOpenForwardOnly遊標方式和其它的加鎖方式混合,它反而會支持填加,刪除和更新。

-----------------------------------------------------------------------------------------------


就啓明星提出的在SQL Server中使用加鎖的問題,我就之前的經驗和收集的一些資料簡單的提出我本身的一些見解,不知道對啓明星是否有所幫助:
通常而言,下面是個典型的打開數據庫的過程。
<%
’遊標類型
Const adOpenForwardOnly = 0
Const adOpenKeyset = 1
Const adOpenDynamic = 2
Const adOpenStatic = 3

’加鎖類型
Const adLockReadOnly = 1
Const adLockPessimistic = 2
Const adLockOptimistic = 3
Const adLockBatchOptimistic = 4
>%

<% set conn = server.createobject(’adodb.connection’) >%
<% set rsmov = server.createobject(’adodb.recordset’) >%
<% conn.open ’soc’, ’’, ’’ >%
<% rsmov.open sqlmov, conn, adopenkeyset, adlockreadonly >%
遊標使用時是比較靈活的,它有時用來描述一個記錄集,有時又是用來描述當前記錄集中某一條記錄的指針。遊標主要是用來創建一個關係數據庫中行/列關係的一種SQL可利用的訪問格。與遊標有關係的技術術語還有一個叫Bookmark的。若是你選擇的遊標方式支持Bookmarks。數據庫將提供有關記錄數目的強大功能。在上面寫出的那麼多遊標方式中,adOpenDynamic是沒有太的用處的,雖然它提供實時顯示數據庫中的記錄的全部更新操做的功能,可是由於並非全部的數據庫都支持該遊標方式,沒有移植性的遊標方式對當前錯綜複雜的數據庫來講真是用處不大。在實際的編程中,我相信你們使用得最頻繁的是adOpenStatic方式,固然這種方式的缺點是不可以就、實時反應出數據庫中內容改變時的情況。若是要想看到數據庫被其它用戶改變的情況,可以使用adOpenKeyse方式(可是它只可以反應出被編輯的改變狀況,也就是說不可以反映出新增和刪除記錄的改變狀況。)
其實上面的內容你們通常均可以在微軟的技術參考資料中找到,下面來講說在使用這些遊標
方式和加鎖方式時要注意到的問題。
1。首先要注意到的是這兩種方式在混合使用時的問題,就是說你同時設置遊標方式和加鎖方式。
除非你是在使用Access數據庫,通常而言當你混合使用時是並不可以獲得你預期想要的遊標方式和加鎖方式的。例如,若是你同時將遊標設置爲adOpenStatic方式,而將加鎖設置爲adLockOptimistic,你將得不到adOpenStatic方式的遊標,你這時使用的遊標方式將是
adOpenKeyset,也就是說你使用ADO的話,它將返回adOpenKeyset的遊標。
2。其次,遊標和加鎖的混合使用還會致使ADO返回的不是你想要的加鎖方式,ADO會改變你的加鎖
方式。例如,在默認狀態下游標方式是adOpenForwardOnly,在使用這種遊標方式的同時若是
你使用的加鎖方式爲-1(就是讓數據源來判斷加鎖方式)或則adLockReadOnly,那麼這種混合方式基本上不支持RecordSet的任何方法,也就是說RecordSet的任何方法將返回False
(你的recordcount,absoultpage,addnew,delete,update等都會返回-1,-1就是表示不支持該屬性),可是這時若是你使用的是adOpenForwardOnly遊標方式和其它的加鎖方式混合,它反而
會支持填加,刪除和更新。

--------------------------------------------------------------------------------------------------------------

          SELECT 語句中「加鎖選項」的功能說明

SQL Server提供了強大而完備的鎖機制來幫助實現數據庫系統的併發性和高性能。用戶既能使用SQL Server的缺省設置也能夠在select 語句中使用「加鎖選項」來實現預期的效果。 本文介紹了SELECT語句中的各項「加鎖選項」以及相應的功能說明。
功能說明: 
NOLOCK(不加鎖)
此選項被選中時,SQL Server 在讀取或修改數據時不加任何鎖。 在這種狀況下,用戶有可能讀取到未完成事務(Uncommited Transaction)或回滾(Roll Back)中的數據, 即所謂的「髒數據」。

HOLDLOCK(保持鎖)
此選項被選中時,SQL Server 會將此共享鎖保持至整個事務結束,而不會在途中釋放。

UPDLOCK(修改鎖)
此選項被選中時,SQL Server 在讀取數據時使用修改鎖來代替共享鎖,並將此鎖保持至整個事務或命令結束。使用此選項可以保證多個進程能同時讀取數據但只有該進程能修改數據。

TABLOCK(表鎖)
此選項被選中時,SQL Server 將在整個表上置共享鎖直至該命令結束。 這個選項保證其餘進程只能讀取而不能修改數據。

PAGLOCK(頁鎖)
此選項爲默認選項, 當被選中時,SQL Server 使用共享頁鎖。

TABLOCKX(排它表鎖)
此選項被選中時,SQL Server 將在整個表上置排它鎖直至該命令或事務結束。這將防止其餘進程讀取或修改表中的數據。

使用這些選項將使系統忽略原先在SET語句設定的事務隔離級別(Transaction Isolation Level)。 請查閱SQL Server 聯機手冊獲取更多信息。
-------------------------------------------------------------------------------------------------------------

1 如何鎖一個表的某一行


A 鏈接中執行

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

begin tran

select * from tablename with (rowlock) where id=3

waitfor delay ’00:00:05’

commit tran

B鏈接中若是執行

update tablename set colname=’10’ where id=3 --則要等待5秒

update tablename set colname=’10’ where id<>3 --可當即執行

2 鎖定數據庫的一個表

SELECT * FROM table WITH (HOLDLOCK)


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

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

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

select * from table with (..)


SELECT 語句中「加鎖選項」的功能說明
  SQL Server提供了強大而完備的鎖機制來幫助實現數據庫系統的併發性和高性能。用戶既能使用SQL Server的缺省設置也能夠在select 語句中使用「加鎖選項」來實現預期的效果。 本文介紹了SELECT語句中的各項「加鎖選項」以及相應的功能說明。
  功能說明: 
  NOLOCK(不加鎖)
  此選項被選中時,SQL Server 在讀取或修改數據時不加任何鎖。 在這種狀況下,用戶有可能讀取到未完成事務(Uncommited Transaction)或回滾(Roll Back)中的數據, 即所謂的「髒數據」。
  
  HOLDLOCK(保持鎖)
  此選項被選中時,SQL Server 會將此共享鎖保持至整個事務結束,而不會在途中釋放。
  
  UPDLOCK(修改鎖)
  此選項被選中時,SQL Server 在讀取數據時使用修改鎖來代替共享鎖,並將此鎖保持至整個事務或命令結束。使用此選項可以保證多個進程能同時讀取數據但只有該進程能修改數據。
  
  TABLOCK(表鎖)
  此選項被選中時,SQL Server 將在整個表上置共享鎖直至該命令結束。 這個選項保證其餘進程只能讀取而不能修改數據。
  
  PAGLOCK(頁鎖)
  此選項爲默認選項, 當被選中時,SQL Server 使用共享頁鎖。
  
  TABLOCKX(排它表鎖)
  此選項被選中時,SQL Server 將在整個表上置排它鎖直至該命令或事務結束。這將防止其餘進程讀取或修改表中的數據。
  
  使用這些選項將使系統忽略原先在SET語句設定的事務隔離級別(Transaction Isolation Level)。 請查閱SQL Server 聯機手冊獲取更多信息。

------------------------------------------------------------------------------------------------------------------------

什幺是事務
事務(Transaction)是併發控制的基本單位。所謂事務,它是一個操做序列,這些操做要幺都執行,要幺都不執行,它是一個不可分割的工做單位。例如,銀行轉賬工做:從一個賬號扣款並使另外一個賬號增款,這兩個操做要幺都執行,要幺都不執行。因此,應該把他們當作一個事務。事務是數據庫維護數據一致性的單位,在每一個事務結束時,都能保持數據一致性。

數據一致性問題
多用戶併發存取同一數據將會致使如下的數據不一致性問題。
• 丟失修改( Lost Update)
在下表中,T一、T二、T3和T4表示順序的時間。
用戶T 1T 2T 3T 4
Ax = 40X = x-30
BX = 40X = x-20

假設用戶A和B都讀取x ( x = 40 ) ,而後分別把x減小30和20。用戶A在t3把改後的x ( x = 10 )寫入數據庫。隨後,用戶B在t4把改後的x ( x = 20 )寫入數據庫。因而,對用戶A而言,他的修改在t4
處丟失了。
• 髒讀數據( Dirty Read)
請看下錶,
用戶T1T2T3T4
Ax = 40X = x + 30X = x - 30rollback
BX = 70X = x-20
用戶A在t2把x增長30(尚沒寫入數據庫),用戶B在t3由數據緩存讀出x = 70。但用戶A在t4時撤消(Undo)了對x的修改,數據庫中仍維持x = 40。但用戶B已把改變的數據( x = 70)取走。
• 不能重複讀(Non-Repeatable Read)
用戶T1T2T3T4T5T6
AX=40Y=30 X+Y=70Z=30 X+Y+Z=100
Bx=40X=X+20CommitX=x-20
用戶A、用戶B分別讀取x = 40後,在t 3用戶A取出y = 30並計算x + y = 70。在t4時用戶B把x增長20,並於t 5把x ( x = 60 )寫入數據庫。在t6時,用戶A取出z ( z = 30 )並繼續計算x + y + z = 100。但若是用戶A爲進行覈算而把x、y、x重讀一次再進行計算,卻出現x + y + z = 120!(x已增長20)。

如何標識一個事務
在SQL Server中,一般事務是指以BEGIN TRAN開始,到ROLLBACK或一個相匹配的COMMIT之間的全部語句序列。ROLLBACK表示要撤消( U n d o)該事務已作的一切操做,回退到事務開始的狀態。COMMIT表示提交事務中的一切操做,使得對數據庫的改變生效。
在SQL Server中,對事務的管理包含三個方面:
• 事務控制語句:它使程序員能指明把一系列操做( Transact - SQL命令)做爲一個工做單
位來處理。
• 鎖機制( Locking):封鎖正被一個事務修改的數據,防止其它用戶訪問到「不一致」的數據。
• 事務日誌( Transaction Log):使事務具備可恢復性。

SQL Server的鎖機制
所謂封鎖,就是一個事務可向系統提出請求,對被操做的數據加鎖( Lock )。其它事務必須等到此事務解鎖( Unlock)以後才能訪問該數據。從而,在多個用戶併發訪問數據庫時,確保不互相干擾。可鎖定的單位是:行、頁、表、盤區和數據庫。
1. 鎖的類型
SQL Server支持三種基本的封鎖類型:共享( S)鎖,排它(X)鎖和更新(U)鎖。封鎖的基本粒度爲行。
1) 共享(S)鎖:用於讀操做。
• 多個事務可封鎖一個共享單位的數據。
• 任何事務都不能修改加S鎖的數據。
• 一般是加S鎖的數據被讀取完畢,S鎖當即被釋放。
2) 獨佔(X)鎖:用於寫操做。
• 僅容許一個事務封鎖此共享數據。
• 其它任何事務必須等到X鎖被釋放才能對該數據進行訪問。
• X鎖一直到事務結束才能被釋放。
3) 更新(U)鎖。
• 用來預約要對此頁施加X鎖,它容許其它事務讀,但不容許再施加U

鎖或X鎖。
• 當被讀取數據頁將要被更新時,則升級爲X鎖。
• U鎖一直到事務結束時才能被釋放。
2. 三種鎖的兼容性
以下表簡單描述了三種鎖的兼容性:
一般,讀操做(SELECT)得到共享鎖,寫操做( INSERT、DELETE)得到獨佔鎖;而更新操做可分解爲一個有更新意圖的讀和一個寫操做,故先得到更新鎖,而後再升級爲獨佔鎖。
執行的命令得到鎖其它進程能夠查詢?其它進程能夠修改?
Select title_id from titlesSYesNo
delete titles where price>25XNoNo
insert titles values( ...)XNoNo
update titles set type=「general」UYesNo
where type=「business」而後XNONo

使用索引下降鎖併發性
咱們爲什幺要討論鎖機制?若是用戶操做數據時儘量鎖定最少的數據,這樣處理過程,就不會等待被鎖住的數據解鎖,從而能夠潛在地提升SQL Server的性能。若是有200個用戶打算修改不一樣顧客的數據,僅對存儲單個顧客信息的單一行進行加鎖要比鎖住整個表好得多。那幺,用戶如何只鎖定行而不是表呢?固然是使用索引了。正如前面所提到的,對存有要修改數據的字段使用索引能夠提升性能,由於索引能直接找到數據所在的頁面,而不是搜索全部的數據頁面去找到所需的行。若是用戶直接找到表中對應的行並進行更新操做,只需鎖定該行便可,而不是鎖定多個頁面或者整個表。性能的提升不只僅是由於在修改時讀取的頁面較少,並且鎖定較少的頁面潛在地避免了一個用戶在修改數據完成以前其它用戶一直等待解鎖的狀況。

事務的隔離級別
ANSI標準爲SQL事務定義了4個隔離級別(isolation level),隔離級別越高,出現數據不一致性的可能性就越小(併發度也就越低)。較高的級別中包含了較低級別中所規定了的限制。
• 隔離級別0:防止「丟失修改」,容許髒讀。
• 隔離級別1:防止髒讀。容許讀已提交的數據。
• 隔離級別2:防止「不可重複讀」。
• 隔離級別3:「可串行化」(serializable)。其含義爲,某組並行事務的一種交叉調度產生的結果和這些事務的某一串行調度的結果相同(可避免破壞數據一致性)。SQL Server支持四種隔離級別,級別1爲缺省隔離級別,表中沒有隔離級別2, 請參考表:
SQL Server支持的隔離級別封鎖方式數據一致性保證
X鎖施加於被修改的頁S鎖施加於被讀取的頁防止丟失修改防止讀髒數據能夠重複讀取
級別0封鎖到事務結束是
級別1(缺省)封鎖到事務結束讀後當即釋放是是
級別3封鎖到事務結束封鎖到事務結束是是是
在SQL Server也指定級別2,但級別3已包含級別2。ANSI-92 SQL中要求把級別3做爲全部事務的缺省隔離級別。
SQL Server用holdlock選項增強S鎖的限制,實現隔離級別3。SQL Server的缺省隔離級別爲級別1,共享讀鎖(S鎖)是在該頁被讀完後當即釋放。在select語句中加holdlock選項,則可以使S鎖一直保持到事務結束才釋放。她符合了ANSI隔離級別3的標準─「可串行化」。

下面這個例子中,在同一事務中對avg ( advance )要讀取兩次,且要求他們取值不變─「可重複讀」,爲此要使用選項holdlock。
BEGIN tran
DECLARE @avg-adv money
SELECT @avg-adv = avg(advance)
FROM titles holdlock
WHERE type = 「business「
if @avg-adv > 5000
SELECT title from titles
WHERE type=「business「 and advance >@avg_adv
COMMIT tran
在SQL Server中設定事務隔離級別的方法有三種:

• 會話層設定
語法以下:
SET TRANSACTION ISOLATION LEVEL
{
READ COMMITTED
| READ UNCOMMITTED
| REPEATABLE READ
| SERIALIZABLE
}
系統提供的系統存儲過程將在級別1下執行,它不受會話層設定的影響。
• 語法層設定
在SELECT、DECLARE cursor及read text語句中增長選項。好比:
SELECT...at isolation{0|read uncommitted}
注意:語法層的設定將替代會話層的設定。
• 利用關鍵詞設定
─在SELECT語句中,加選項holdlock則設定級別3
─在SELECT語句中,加noholdlock則設定級別0

以下程序清單中所列的腳本實例在authors表上持有一個共享鎖,它將用戶檢查服務器當前活動的時間推遲兩分鐘。
程序清單測試事務隔離等級
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
BEGIN TRAN
SELECT *
FROM authors
WHERE au_lname = ’Green’
WAITFOR DELAY ’00:02:00’
ROLLBACK TRAN
GO
Activity Legend(活動圖標)代表:當SQL Server檢索數據時會去掉頁面表意向鎖。Current Activity窗口(見圖3 - 3 )顯示共享鎖一直被保持直到事務完成爲止(也就是說,直到WAITFOR和ROLLBACK TRAN語句完成)。
使用鎖定優化程序提示
讓咱們再深刻考察程序清單的實例。經過改變優化程序提示,用戶能夠令SQL Server在authors表上設置一個獨佔表鎖(如程序所示)。
BEGIN TRAN
SELECT *
FROM authors (tablockx)
WHERE au_lname = ’Green’
WAITFOR DELAY ’00:02:00’
ROLLBACK TRAN
GO


------------------------------------------------------------------------------------------------------------------------
                                
HOLDLOCK 將共享鎖保留到事務完成,而不是在相應的表、行或數據頁再也不須要時就當即釋放鎖。HOLDLOCK 等同於 SERIALIZABLE。
NOLOCK 不要發出共享鎖,而且不要提供排它鎖。當此選項生效時,可能會讀取未提交的事務或一組在讀取中間回滾的頁面。有可能發生髒讀。僅應用於 SELECT 語句。
PAGLOCK 在一般使用單個表鎖的地方採用頁鎖。
READCOMMITTED 用與運行在提交讀隔離級別的事務相同的鎖語義執行掃描。默認狀況下,SQL Server 2000 在此隔離級別上操做。
READPAST 跳過鎖定行。此選項致使事務跳過由其它事務鎖定的行(這些行日常會顯示在結果集內),而不是阻塞該事務,使其等待其它事務釋放在這些行上的鎖。READPAST 鎖提示僅適用於運行在提交讀隔離級別的事務,而且只在行級鎖以後讀取。僅適用於 SELECT 語句。
READUNCOMMITTED 等同於 NOLOCK。
REPEATABLEREAD 用與運行在可重複讀隔離級別的事務相同的鎖語義執行掃描。
ROWLOCK 使用行級鎖,而不使用粒度更粗的頁級鎖和表級鎖。
SERIALIZABLE 用與運行在可串行讀隔離級別的事務相同的鎖語義執行掃描。等同於 HOLDLOCK。
TABLOCK 使用表鎖代替粒度更細的行級鎖或頁級鎖。在語句結束前,SQL Server 一直持有該鎖。可是,若是同時指定 HOLDLOCK,那麼在事務結束以前,鎖將被一直持有。
TABLOCKX 使用表的排它鎖。該鎖能夠防止其它事務讀取或更新表,並在語句或事務結束前一直持有。
UPDLOCK 讀取表時使用更新鎖,而不使用共享鎖,並將鎖一直保留到語句或事務的結束。UPDLOCK 的優勢是容許您讀取數據(不阻塞其它事務)並在之後更新數據,同時確保自從上次讀取數據後數據沒有被更改。
XLOCK 使用排它鎖並一直保持到由語句處理的全部數據上的事務結束時。可使用 PAGLOCK 或 TABLOCK 指定該鎖,這種狀況下排它鎖適用於適當級別的粒度




轉自:http://bbs.csdn.net/topics/310190864 (一樓到四樓)程序員

相關文章
相關標籤/搜索