多客戶環境下VB數據庫編程之(7)
頁面鎖定的鎖定方案
如前所述,Microsoft Jet不能鎖定單個的記錄,每次讀、寫以及鎖定的都是一頁數據,面不是一個記錄。根據記錄的大小,一頁可能包含多個記錄。當鎖定一個記錄時,就會鎖定那一頁上的所有記錄。
在高并發應用程序中,要求對指定記錄提供暢通無阻的訪問。可以用不同的策略來實現設計。
1.使用Text類型。可以用Text數據類型把字段添加到表中,直到記錄長度超過1024個字節。由于Text是變長數據類型,必須顯式地用數據來填補字段以獲得一個定長格式。同時,這種技術可能會降低性能,因為如果每個記錄都占用2K磁盤空間,則數據庫的長度將會增加。因此,建議不要使用Text 數據類型。
2. 使用CHAR類型。SQL DDL CHAR 是一種定長數據類型。如果使用這種類型,則可不必用數據來填補字段。使用CHAR數據類型是實現這種技術的最簡單而且保險的唯一方法。
3.使用開放鎖定。另一種策略是:在任何地方都使用開放方式鎖定。雖然開放式鎖定不能避免頁面鎖定,但它可以使記錄被鎖定的時間最短,因此降低了不需要鎖定的記錄也被鎖定的可能性。
4.使用自定義的鎖定方案。有時候,頁面鎖定不能滿足需要,而開放式鎖定也可能無法滿足需要。在這種情況下,可以考慮使用自定義的鎖定方案。當一個記錄被鎖定時,可以用一個鎖定表來標識。鎖定表存儲記錄的鍵值、鎖定狀態(鎖定或未鎖定)以及鎖定記錄的用戶名等。自定義鎖定方案的實現需要大量的設計、實現以及測試時間。在許多情況下,它不能與內置的Microsoft Jet的功能重復。例如,即使實現單記錄鎖定,處理基于多個表的記錄集的數據也是非常困難的,因為必須標識所有表,而這些表都包含必須鎖定的記錄。當自定義鎖定方案只影響幾個表,而且不是基于一個具有復雜連結和關系的數據模型時,使用自定義鎖定方案較為適宜。
頁面鎖定中的錯誤處理
當使用頁面鎖定時,必須在代碼中檢查是否成功地實現了鎖定。在開始時應禁止錯誤處理程序,然后嘗試完成初始化一個鎖定、檢查錯誤,最后允許錯誤處理程序。在多用戶環境下,所遇到的頁面鎖定錯誤有三種,見表。
錯誤代碼和出錯信息 原因和建議的操作
3186 不能存儲;當前正被機器
3197因為和另一個用戶試圖同時改變同一個數據,所以MicrosoftJet數據庫引擎終止了該過程 在打開記錄集或最后一次從記錄中讀取數據之后,另一個用戶對當前記錄作了更改,并使用Edit方法或Update方法時,就會產生這個錯誤。如果在使用Edit方法時產生了這個錯誤,就要用當前數據來刷新用戶的數據視圖然后再試一次Edit方法。如果這個錯誤是在使用update方法時發生的,則是因為使用了開放式鎖定,并且在使用Edit方法后記錄發生了變更。在這種情況下,應通知用戶,其他人已經改變了數據。可以顯示出當前數據并讓用戶選擇:是覆蓋其他用戶的變更,還是取消編輯
3260不能更新;當前,被機器
用錯誤代碼和出錯信息可以測試記錄是否被鎖定。下面的過程可用來檢測當前記錄是否在一個鎖定的頁面上:
Function RecordLocked(rst As Recordset)AsBoolean
Dim blnLock As Boolean
On Error GoToErrorHandler
blnLock=rst.LockEdits '保存LockEdits屬性的當前值
rst.LockEdits=True '設置保守式鎖定
rst.Edit '試著編輯記錄,如果記錄被鎖定,則會產生錯誤3197
RecordLocked=False
rst.CancelUpdate
rst.LockEdits=blnLock '恢復LockEdits屬性的值
EXit FUnction
ErrorHandler:
Select Case Err
Case 3197:
Resume Next
Case Else
RecordLocked=True
Resume Next
EXit Function
End Select
End Function
該過程把記錄集的鎖定設置為保守式,并編輯記錄,以測試當前記錄是否在一個被鎖定的頁面上,如果記錄被鎖定,則會產生一個錯誤(3197)。該過程有一個參數,即rst,它是Recordset對象。調用該過程,將返回一個布爾值。為了調用該過程,可以在窗體上畫一個命令按鈕,然后編寫如下事件過程:
Private Sub Command1_Click()
Dim dbs As Database
Dim tb As Recordset
Dim bl As Boolean
Set dbs=opendatabase("c:dbdirdbl.mdb",dbopenDynaset)
Settb=dbs.OpenRecordset("tablel",dbOpenTable)
bl=RecordLocked(tb)
End Sub
在該事件過程中,打開一個數據庫和該數據庫中的表,然后用記錄集作為參數調用上述過程,調用結果放在變量bl中。如果記錄被鎖定,則返回值為True,否則為False。