1、引言
筆者在使用Visual FoxPro 6.0編制超市綜合信息管理系統(tǒng)時(shí),由于某些參數(shù)的設(shè)置不當(dāng),或某些命令使用不當(dāng),曾走過(guò)一些彎路,總結(jié)起來(lái)體會(huì)頗多。
2、Visual FoxPro 6.0的幾個(gè)不盡如意的地方
2.1 Visual FoxPro 6.0的一個(gè)bug
筆者在設(shè)計(jì)一個(gè)產(chǎn)品庫(kù)存查詢(xún)表單(form)kccx.scx時(shí),其中一個(gè)網(wǎng)格(grid)grid1顯示查詢(xún)內(nèi)容,運(yùn)行此表單,因尚未選擇查詢(xún)條件,網(wǎng)格顯示所有產(chǎn)品的庫(kù)存情況。因此,在表單kccx.scx的active事件中加入以下程序,使網(wǎng)格grid1顯示表dspbmk(產(chǎn)品庫(kù)存庫(kù))的全部?jī)?nèi)容:
select * from dspbmk into table tj
thisform.grid1.recordsource="tj"
thisform.grid1.scrollbars=3
thisform.refresh
系統(tǒng)剛開(kāi)始運(yùn)行時(shí),由于產(chǎn)品記錄個(gè)數(shù)少并未發(fā)現(xiàn)問(wèn)題,但隨著產(chǎn)品的增加,發(fā)現(xiàn)進(jìn)入此表單很慢。通過(guò)將SET SAFETY 設(shè)置為ON,單步調(diào)試,發(fā)現(xiàn)上述程序的第一條SELECT語(yǔ)句重復(fù)執(zhí)行若干次。將此段程序移到表單的init事件后,程序執(zhí)行正常。或者將上段程序該為:
select * from dspbmk into cursor tj
thisform.grid1.recordsource="tj"
thisform.grid1.scrollbars=3
thisform.refresh
程序也執(zhí)行正常。
同樣,將上段程序放入頁(yè)框(pageframe)的某一頁(yè)(page)的active事件中,也會(huì)出現(xiàn)同樣的問(wèn)題。筆者并未找到關(guān)于此問(wèn)題解釋的相關(guān)資料,也許這是Visual FoxPro 6.0的一個(gè)bug。
2.2 慎用VFP的緩沖區(qū)功能
Visual FoxPro 6.0提供了緩沖區(qū)功能,只要將緩沖區(qū)(buffering)狀態(tài)設(shè)為2、3、4、5,那么對(duì)表或記錄的操作只在緩沖區(qū)中進(jìn)行,再通過(guò)tableupdate()函數(shù)將修改傳送到表中,或通過(guò)tablerevert()函數(shù)取消對(duì)表的修改。VFP的這種功能大大簡(jiǎn)化了程序的編寫(xiě)。但提醒編程者注意:當(dāng)使用表緩沖(buffering狀態(tài)設(shè)為5)功能時(shí),若一次修改的記錄數(shù)太多(比如400條以上),當(dāng)執(zhí)行tableupdate()函數(shù)對(duì)表進(jìn)行真正修改時(shí),發(fā)現(xiàn)緩沖區(qū)的數(shù)據(jù)丟失,本次修改失敗。
2.3 多使用FLUSH命令
假定有一表單,要連續(xù)執(zhí)行若干小時(shí),其中經(jīng)常要對(duì)某個(gè)表操作,在表單的load事件中打開(kāi)此表,此后該表一直處于打開(kāi)狀態(tài),通過(guò)APPE、DELE、REPL等操作對(duì)表進(jìn)行了上千條記錄的操作,但當(dāng)退出后有時(shí)會(huì)發(fā)現(xiàn)當(dāng)天的數(shù)據(jù)并未保存,盡管VFP幫助文件中介紹5分鐘后會(huì)自動(dòng)FLUSH。在每次操作后加入FLUSH語(yǔ)句,再?zèng)]出現(xiàn)以上問(wèn)題。
3、Visual FoxPro 6.0網(wǎng)絡(luò)程序設(shè)計(jì)應(yīng)注意的幾個(gè)問(wèn)題
在單用戶(hù)狀態(tài)下,數(shù)據(jù)庫(kù)的使用沒(méi)有共享和獨(dú)占概念,用戶(hù)可以隨意對(duì)表進(jìn)行增、刪、改、查等操作,不受任何影響。但是,在網(wǎng)絡(luò)環(huán)境下就不一樣,當(dāng)表被打開(kāi)時(shí),如果兩個(gè)用戶(hù)對(duì)一個(gè)表同時(shí)進(jìn)行修改、刪除等操作,后果將不堪設(shè)想。所以在網(wǎng)絡(luò)環(huán)境下表的打開(kāi)有兩種方式:一是共享方式,表示這個(gè)表可以被任何用戶(hù)操作;二是獨(dú)占方式,表示這個(gè)表只能被一個(gè)用戶(hù)操作。例如,對(duì)于商場(chǎng)管理系統(tǒng),由于數(shù)據(jù)量大,需經(jīng)常對(duì)表進(jìn)行數(shù)據(jù)整理(需執(zhí)行PACK、ZAP等操作),當(dāng)系統(tǒng)管理員進(jìn)行數(shù)據(jù)整理時(shí)表必須以獨(dú)占方式打開(kāi);而前臺(tái)收款和后臺(tái)操作同時(shí)進(jìn)行時(shí),表必須以共享方式打開(kāi)。那么如何解決多個(gè)用戶(hù)同時(shí)對(duì)表操作而不致出現(xiàn)問(wèn)題呢?下面筆者談幾點(diǎn)體會(huì)。
3. 1 一般的解決方法
文件或記錄的加鎖與解鎖是網(wǎng)絡(luò)程序設(shè)計(jì)中經(jīng)常用到的方法。VFP提供了FLOCK()、RLOCK()和LOCK()函數(shù)對(duì)文件和記錄進(jìn)行加鎖,一個(gè)文件或記錄加鎖后,只能由加鎖用戶(hù)進(jìn)行讀寫(xiě),其他用戶(hù)只能讀不能寫(xiě)。當(dāng)對(duì)記錄或文件進(jìn)行修改或刪除時(shí),必須加鎖。當(dāng)對(duì)文件操作完畢應(yīng)及時(shí)解鎖,VFP提供UNLOCK命令對(duì)指定工作區(qū)解鎖。如:
do while !flock()
wait window ‘正在鎖定數(shù)據(jù)庫(kù)請(qǐng)稍候!’Timeout 0.05
enddo
:
unlock
當(dāng)對(duì)文件或記錄加鎖時(shí),若由于某種原因沒(méi)有鎖住,可以再試加鎖操作,并可指定加鎖次數(shù)或試鎖的時(shí)間。VFP提供了SET REPROCESS TO命令來(lái)確定如何控制失敗的記錄或文件加鎖。此外,VFP還提供SET REFRESH TO命令控制多長(zhǎng)時(shí)間后顯示網(wǎng)絡(luò)中其他用戶(hù)對(duì)記錄所做的修改。
3.2 慎用VFP的隱含鎖定功能
當(dāng)VFP處于隱含鎖定狀態(tài)(即SET LOCK 設(shè)置為ON)時(shí),執(zhí)行某些命令時(shí)將自動(dòng)對(duì)表加鎖。這些命令包括:
AVERAGE、CALCULATE、LIST、DISPLAY、SORT、INDEX、COUNT、TOTAL、SUM、COPY TO、COPY TO ARRAY 、REPORT、JOIN、LABEL。
在網(wǎng)絡(luò)環(huán)境中,必須將SET LOCK 設(shè)置為OFF,以免影響其他用戶(hù)的正常使用。例如,一個(gè)商場(chǎng)管理系統(tǒng),后臺(tái)正在打印商品信息,若SET LOCK 設(shè)置為ON,則此時(shí)商品信息表將加鎖,前臺(tái)銷(xiāo)售需對(duì)商品信息表的商品庫(kù)存進(jìn)行減操作,也需對(duì)商品信息表加鎖。此時(shí)將陷入鎖定等待狀態(tài),影響前臺(tái)收款。
3.3 使用VFP的多記錄鎖功能時(shí)要及時(shí)對(duì)記錄開(kāi)鎖
Visual FoxPro 6.0將SET MULTILOCKS設(shè)置為ON,即設(shè)置多記錄鎖,表示同時(shí)對(duì)多條記錄加鎖。對(duì)此功能的使用需謹(jǐn)慎,一定要及時(shí)開(kāi)鎖,否則容易引起死鎖。假定有一個(gè)網(wǎng)絡(luò)版的商場(chǎng)銷(xiāo)售系統(tǒng),許多表單的對(duì)表操作采用了表緩沖區(qū)狀態(tài),由于VFP規(guī)定使用緩沖區(qū)功能必須將SET MULTILOCKS設(shè)置為ON。所以系統(tǒng)運(yùn)行時(shí)是處于多鎖狀態(tài)。前臺(tái)銷(xiāo)貨存盤(pán)時(shí)要對(duì)商品信息表(dspbmk.dbf)中的商品庫(kù)存量進(jìn)行修改,在存盤(pán)按鈕的click事件中加入以下程序段:
sele sp /* 銷(xiāo)售商品清單
go top
do while .not. eof()
sele dspbmk
seek sp.spbh
do while !rlock()
wait window ‘正在鎖定數(shù)據(jù)庫(kù)請(qǐng)稍候!’Timeout 0.05
enddo
repl kcl with kcl-sp.sl
sele sp
skip
enddo
sele dspbmk
unlock in dspbmk
程序?qū)γ總(gè)記錄修改后并未及時(shí)開(kāi)鎖,在全部修改完后才開(kāi)鎖。
假定有甲乙兩個(gè)收款臺(tái),前臺(tái)甲正在賣(mài)編號(hào)為1、2、3的商品,前臺(tái)乙正在賣(mài)編號(hào)為3、2、1的商品,甲存盤(pán)時(shí)首先鎖定1商品,庫(kù)存量修改完后記錄指針移動(dòng),又鎖定了2商品的記錄,處理完后試圖鎖定2商品;而前臺(tái)先鎖定了3商品記錄,處理完后試圖鎖定2商品。這時(shí)就發(fā)生死鎖,造成系統(tǒng)癱瘓。糾其原因,主要因?yàn)镾ET MULTILOCKS設(shè)置為ON了,而以上程序卻未對(duì)記錄及時(shí)開(kāi)鎖。