?? -
字號:
$OPEN mycurs//打開滾動游標
for(;;)
{$FETCH mycurs INTO $Id,$Mdeposit,$Mpayout,$Mbalance; //從游標中讀取記錄值
if sqlcode=SQLNOTFOUND then exit; //如果讀完,退出循環
….//顯示記錄內容給用戶看
….//如果用戶決定要修改記錄,則繼續執行
$DECLARE mycurs_update CURSOR FOR SELECT Mdeposit,Mpayout,Mbalance
FROM Acount WHERE Id=$Id; //定義更新游標
$FETCH mycurs_UPDATE INTO $Mdeposit,$Mpayout,$Mbalance; //讀取數值
$UPDATE acount SET (Mdeposit,Mpayout,Mbalance)= ( $Mdeposit,$Mpayout,$Mbalance)
WHERE CURRENT of mycurs_update; //更新數值
(三)利用開發工具的支持。
許多數據庫開發工具都有一些方便的選項或部件來支持并發控制,而不論DBMS是否支持并發控制。我們看一下Delphi與Powerbuilder的并發控制方法。
Delphi是一個優秀的c/s開發工具,它用來查詢數據的數據庫控件是TQuery,它可以和TUpdatesql控件有機的結合起來完成數據庫表數據的瀏覽和更新。其中在TQuery控件中有一個屬性是Updatemod(修改模式),他有三種選擇:(1)upWhereAll:在瀏覽和修改期間只要有人修改了此記錄某個列,那么不管你是否修改過這個列,你的修改在提交時都不能成功。(2)upWhereChanged:只根據鍵值列和你已經修改的列來決定你的修改是否成功,如果別人所修改的本記錄的列與你修改的列不相交,那么你的修改仍然是成功的。(3)UpWhereOnly:只根據鍵值是否修改來判斷你的更新是否成功。
與TQuery控件配套使用的TUpdatesql控件根據所指定的修改屬性,自動生成所需的更新語句,非常方便。第2種模式是最常用的修改模式,只要別人對記錄所做的修改不與自己的重合,那么就會提交成功,這即保證不會發生數據的丟失、覆蓋,并且具有較高的并發度。還是上邊的例子,比如說客戶瀏覽記錄后修改的是記錄中Mpayout、Mbalance兩列,那么在修改選項upWhereChanged下,Tupdatesql控件所生成的SQL語句是:
UPDATE acount SET (Mpayout,Mbalance)=($Mpayout,$Mbalance)
WHERE Key=Key_old and Mpayout=Mpayout_old and Mbalance=Mbalance_old;
其中Key_old,Mpayout_old和Mbalance_old是delphi替用戶所生成的中間變量,暫存原先數據記錄的舊值,用于比較舊值與現在的值是否相等,如果不相等,說明已經有別的用戶更改了該記錄,那么為了避免丟失修改,該用戶的更新操作不能完成,反之則可以完成。那么當出納員修改帳戶時,如果別人已經修改了這個帳戶,那么他的這次修改是不成功的,必須重新刷新記錄才可能成功修改。對上面的例子進行這種改造,就可以避免銀行的損失。
與Delphi媲美的一個另一個工具是著名的Powerbuilder,在其DataWindows的設計中,我們選擇菜單Rows|Update…,會出現Specify Update Characteristics的設置窗口,在這個窗口中我們設置Update語句中Where子句的生成,以此來進行并發控制。在這里有三個選項: (1)Key Columns:生成的Where子句中只比較表中的主鍵列的值與最初查詢時是否相同來確定要修改的記錄。與Delphi中的UpWhereOnly選項對應。 (2)Key and Updateable Columns:生成的Where子句比較表中主鍵列和可修改列的值與最初查詢時否是相同。與Delphi的upWhereall相對應。 (3)Key and Modified Columns:與Delphi的upWhereChanged選項對應。Where子句比較主鍵和要修改的列。
(四)調整應用。
有的數據庫沒有提供并發控制的功能,例如Foxpro等,象Mysql的某些版本也不支持事務。而且有的開發工具(例如一些網頁腳本編輯器等)也沒有提供實現并發控制的部件,那么要實現并發控制,就只能借助于調整我們的應用程序和數據庫結構的辦法了。
可以按照封鎖的基本思想來調整應用。在需要進行并發控制的數據庫表中增加一個鎖字段,這個字段可以是一個布爾型變量,為true則為鎖定,為false則為空閑。此時表的結構變為:
列名稱 列代碼 列類型
帳戶號 Id(鍵值列) Char(10)
戶主 Uname Char(10)
存入金額 Mdeposit Currency
支出金額 Mpayout Currency
存款余額 Mbalance Currency
鎖 Lock Boolean
如果一個應用中,客戶查詢這個表時,可以修改表的記錄,那么為了防止別的客戶在該用戶編輯某記錄期間修改這個記錄,那么就需要客戶在瀏覽到該記錄的數據時,給該記錄加上鎖(即將鎖字段改為true),修改完畢后釋放鎖(將鎖字段改為false)。別的客戶要修改這個表的記錄的話就先檢測一下該記錄有沒有被加鎖,如果已經加鎖,則不能進行修改。如果鎖字段空閑,那么首先給該記錄加鎖,然后取記錄給客戶瀏覽、編輯,在此期間別的客戶不能修改記錄。這就很有效的防止了丟失修改。
上面是一種常用的方法,但是也不是完全沒有缺點,它可能會產生這樣一種副作用:當一個用戶決定修改一個記錄時,該記錄被鎖定,等待用戶修改,但此時正好用戶離開了,那么這條記錄將一直被鎖定直到用戶提交(可能是幾個小時之后了)或者會話超時,那么在這一段時間內別的用戶就不可以更改這一條記錄,導致并發度很低。有一個繞過這個問題的解決辦法就是將瀏覽到的記錄記到old_record(自定義的變量)中,再將old_record的內容拷貝到一個新記錄new_record(自定義的變量)中,用戶編輯new_record,當提交new_record時比較old_record和原先的記錄,如果不一樣,則表明已經有用戶修改了原先的記錄,此時把對new_record做的修改放棄;反之則將其內容提交。
上邊的方法還有一個小小的不足:在做新舊記錄的比較的時候必須比較整條記錄,費時間而且程序寫起來比較麻煩。可以考慮在原先的表中增添一個時間戳列(此時可以取消lock列),那么此時表的結構變為:
列名稱 列代碼 列類型
帳戶號 Id(鍵值列) Char(10)
戶主 Uname Char(10)
存入金額 Mdeposit Currency
支出金額 Mpayout Currency
存款余額 Mbalance Currency
時間戳 Date Datetime
當瀏覽記錄時將時間戳值記到old_date(自定義變量)中,再將記錄內容記到一個新記錄new_record中,用戶編輯new_record,當提交new_record時比較old_date和原先的記錄中的時間戳,如果不一樣,則表明已經有用戶修改了原先的記錄,此時把對new_record做的修改放棄;反之則將其內容提交。更新語句為:
UPDATE acount SET (Mpayout,Mbalance,Date)=($Mpayout,$Mbalance,$Date)
WHERE Key=Key_old and Date=$Date_old;
五.總結
我們通常說的并發控制是指在DBMS(數據庫管理系統)內部進行的并發控制。而并發控制的方法非常豐富,遠不止此。可以借助于數據庫本身的能力,也可以利用開發工具,還可以通過調整自己的程序來實現。在數據庫應用中,進行并發控制的方法、實現途徑多種多樣。在選擇時所依據的基本原則就是:數據一致性一定要合乎應用的需要,在此基礎上,盡量提高并發度。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -