Pages

2013年8月16日 星期五

鎖的問題

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 連線手冊獲取更多資訊。  
-------------------------------------------------------------------------------------------------------------

如何鎖一個表的某一行


連接中執行

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 --可立即執行

鎖定資料庫的一個表

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
在下表中,T1T2T3T4表示順序的時間。
用戶T 1T 2T 3T 4
Ax = 40X = x-30
BX = 40X = x-20

假設用戶AB都讀取x ( x = 40 ) ,然後分別把x減少3020。用戶At3把改後的x ( x = 10 )寫入資料庫。隨後,用戶Bt4把改後的x ( x = 20 )寫入資料庫。於是,對用戶A而言,他的修改在t4
處丟失了。
• 髒讀數據( Dirty Read
請看下表,
用戶T1T2T3T4
Ax = 40X = x + 30X = x - 30rollback
BX = 70X = x-20
用戶At2x增加30(尚沒寫入資料庫),使用者Bt3由資料緩存讀出x = 70。但用戶At4時撤銷(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時用戶Bx增加20,並於t 5x ( x = 60 )寫入資料庫。在t6時,用戶A取出z ( z = 30 )並繼續計算x + y + z = 100。但如果用戶A為進行核算而把xyx重讀一次再進行計算,卻出現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)獲得共用鎖,寫操作( INSERTDELETE)獲得獨佔鎖;而更新操作可分解為一個有更新意圖的讀和一個寫操作,故先獲得更新鎖,然後再升級為獨佔鎖。
執行的命令獲得鎖其它進程可以查詢?其它進程可以修改?
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已包含級別2ANSI-92 SQL中要求把級別3作為所有事務的缺省隔離級別。
SQL Serverholdlock選項加強S鎖的限制,實現隔離級別3SQL 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下執行,它不受工作階段層設定的影響。
• 語法層設定
SELECTDECLARE cursorread 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 )顯示共用鎖一直被保持直到事務完成為止(也就是說,直到WAITFORROLLBACK TRAN語句完成)
使用鎖定優化程式提示
讓我們再深入考察程式清單的實例。通過改變優化程式提示,使用者可以令SQL Serverauthors表上設置一個獨佔表鎖(如程式所示)
BEGIN TRAN
SELECT *
FROM authors (tablockx)
WHERE au_lname = ’Green’
WAITFOR DELAY ’00:02:00’
ROLLBACK TRAN
GO


0 意見: