================================================================================================
var
flag: string;
begin
try
flag := 'A';
Exit;
flag := 'B';
finally
flag := 'C';
end;
flag := 'D';
end;
================================================================================================
分析:不論try子句如何結(jié)束,finally 子句總是被執(zhí)行。(多謝ylmg網(wǎng)友)
2、一個能讓整個系統(tǒng)停止運作的小問題
在數(shù)據(jù)庫系統(tǒng)設(shè)計中,經(jīng)常使用事務(wù)操作來保證數(shù)據(jù)的完整性,但是設(shè)計不當(dāng),卻容易產(chǎn)生比較大的影響,下面舉個例子說明雖然數(shù)據(jù)完整性保證了,但是可能令到系統(tǒng)完全停止運作:
================================================================================================
AdoConnection1.BeginTrans;
try
...
if application.MessageBox('是否確定刪除?', '詢問', MB_YESNO+MB_ICONQUESTION)<>IDYes then //(1)
begin
...
end;
Application.MessageBox('操作失敗', '警告', MB_OK); //(2)
AdoConnection1.CommitTrans;
except
Application.MessageBox('操作失敗', '警告', MB_OK); //(3)
AdoConnection1.RollbackTrans;
end;
================================================================================================
分析:上面代碼中的問題都是由于(1)、(2)、(3)的Application.MessageBox引起,但是引起問題的并不是Application.MessageBox本身,而是它將程序掛起,需要用戶干預(yù)后,才繼續(xù)執(zhí)行后面的操作;如果用戶這時候離開了計算機,或者沒有對這些對話框進行確定操作的話,可想而知,整個系統(tǒng)因為這個事務(wù)沒有結(jié)束而通通處于等待狀態(tài)了。
為了避免這個問題,原則有兩個:
(1)、事務(wù)啟動后,無需用戶干預(yù),程序可以自動結(jié)束事務(wù);
(2)、在事務(wù)里面做時間最短的操作。
3、try...except...end結(jié)構(gòu)
下面舉個例子來說明try結(jié)構(gòu),還是使用事務(wù)操作的例子:
有問題的代碼:
================================================================================================
try
...
AdoConnection1.BeginTrans;
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
================================================================================================
分析:如果try之后到AdoConnection1.BeginTrans這段代碼中出現(xiàn)異常,將跳轉(zhuǎn)到AdoConnection1.RollbackTrans執(zhí)行,但是AdoConnection1因為出錯并沒有啟動事務(wù),所以AdoConnection1.RollbackTrans執(zhí)行時出錯了。
正確的代碼: ================================================================================================
AdoConnection1.BeginTrans;
try
...
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
================================================================================================
總之,try的架構(gòu)是用來保護異常的操作的,try...except之間的產(chǎn)生異常都會執(zhí)行except...end之間的操作,設(shè)計try命令時一定要注意架構(gòu)的合理性。
4、欺騙了自己的事務(wù)保護
在做數(shù)據(jù)庫應(yīng)用軟件時,我們經(jīng)常需要碰到下面的問題:對原有數(shù)據(jù)進行判斷,然后做出相應(yīng)的修改。這個問題看似比較簡單,但是如果考慮到網(wǎng)絡(luò)上還有別的人在使用同一個系統(tǒng),那么,你就不的不考慮可能被意外改變的問題了。我的同事比較粗心,雖然在我的提示下考慮了多用戶問題,但是他還是寫下了有問題的代碼:
================================================================================================
var
adsTemp: TAdoDataSet;
isOk: boolean;
begin
adsTemp := TAdoDataSet.Create(self);
try
adsTemp.Connection := AdoConnection1;
adsTemp.CommandText := 'select fid, fnumber from tb1 where fid=120';
adsTemp.Open;
isOk := adsTemp.FieldByName('fnumber').AsInteger>100;
finally
adsTemp.Free;
end;
if not isOk then
Exit;
AdoConnection1.BeginTrans;
try
AdoConnection1.Execute('update tb1 set ffull=ffull + 1 from tb1 where fid=120';
...
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
end;
================================================================================================
分析:不知大家看出問題來了沒有,在AdoConnection1.BeginTrans之前判斷數(shù)據(jù),然后使用AdoConnection1.Execute改變數(shù)據(jù),如果這個數(shù)據(jù)是共享的,那么在判斷之后到AdoConnection1.BeginTrans之前的這段時間里頭,tb1的數(shù)據(jù)可能已經(jīng)發(fā)生了改變,這個事務(wù)保護是沒有用處的。
正確的方法是判斷和修改必須是同一份數(shù)據(jù),下面示例了有兩個方法(區(qū)別在于啟動事務(wù)的位置不相同):
代碼1(使用事務(wù)保護以后,判斷的和修改的是同一數(shù)據(jù)):
================================================================================================
var
adsTemp: TAdoDataSet;
isOk: boolean;
begin
AdoConnection1.BeginTrans;
try
adsTemp := TAdoDataSet.Create(self);
try
adsTemp.Connection := AdoConnection1;
adsTemp.CommandText := 'select fid, fnumber, ffull from tb1 where fid=120';
adsTemp.Open;
if adsTemp.FieldByName('fnumber').AsInteger>100 then
begin
adsTemp.Edit;
adsTemp.FieldByName('ffull').AsInteger := adsTemp.FieldByName('ffull').AsInteger + 1;
adsTemp.Post;
end;
finally
adsTemp.Free;
end;
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
end;
================================================================================================
代碼2(使用異常捕捉,假如判斷和修改的不是同一份數(shù)據(jù),adsTemp.Post時會出現(xiàn)異常,這個是ADODataSet對象具有的特性):
================================================================================================
var
adsTemp: TAdoDataSet;
isOk: boolean;
begin
adsTemp := TAdoDataSet.Create(self);
try
adsTemp.Connection := AdoConnection1;
adsTemp.CommandText := 'select fid, fnumber, ffull from tb1 where fid=120';
adsTemp.Open;
if adsTemp.FieldByName('fnumber').AsInteger>100 then
begin
AdoConnection1.BeginTrans;
try
adsTemp.Edit;
adsTemp.FieldByName('ffull').AsInteger := adsTemp.FieldByName('ffull').AsInteger + 1;
adsTemp.Post;
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
end;
finally
adsTemp.Free;
end;
end;
新聞熱點
疑難解答
圖片精選