轉自高手關於SQL 鎖的敘述。。

好文章,拿來慢慢研究。

鎖的概述

一. 爲什麼要引入鎖

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

【丟失更新】
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)
在下表中,T1、T2、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 (一樓到四樓)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章