1. Exit method
I originally thought that the process would exit immediately after the Exit method was executed, but I changed my mind after I actually made an example to test it. Please look at this
For example, flag is finally assigned the value 'C'.
================================================== ==============================================
var
flag: string;
begin
try
flag := 'A';
Exit;
flag := 'B';
finally
flag := 'C';
end;
flag := 'D';
end;
================================================== ==============================================
Analysis: No matter how the try clause ends, the finally clause is always executed. (Thank you ylmg netizen)
2. A small problem that can bring the entire system to a halt
In database system design, transaction operations are often used to ensure data integrity. However, improper design can easily have a relatively large impact. The following example illustrates that although data integrity is guaranteed, the system may completely stop functioning:
================================================== ==============================================
AdoConnection1.BeginTrans;
try
...
if application.MessageBox('Are you sure to delete?', 'Question', MB_YESNO+MB_ICONQUESTION)<>IDYes then //(1)
begin
...
end;
Application.MessageBox('Operation failed', 'Warning', MB_OK); //(2)
AdoConnection1.CommitTrans;
except
Application.MessageBox('Operation failed', 'Warning', MB_OK); //(3)
AdoConnection1.RollbackTrans;
end;
================================================== ==============================================
Analysis: The problems in the above code are all caused by Application.MessageBox in (1), (2), and (3), but it is not Application.MessageBox itself that causes the problem, but it hangs the program and requires user intervention. , and then continue to perform subsequent operations; if the user leaves the computer at this time, or does not confirm the operation of these dialog boxes, it is conceivable that the entire system is in a waiting state because this transaction has not ended.
To avoid this problem, there are two principles:
(1) After the transaction is started, the program can automatically end the transaction without user intervention;
(2) Do the shortest operation in the transaction.
3. try...except...end structure
The following is an example to illustrate the try structure, or an example of using transaction operations:
The code in question:
================================================== ==============================================
try
...
AdoConnection1.BeginTrans;
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
================================================== ==============================================
Analysis: If an exception occurs in the code after try to AdoConnection1.BeginTrans, it will jump to AdoConnection1.RollbackTrans for execution. However, AdoConnection1 did not start the transaction due to an error, so an error occurred during execution of AdoConnection1.RollbackTrans.
Correct code: ============================================== ==================================================
AdoConnection1.BeginTrans;
try
...
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
================================================== ==============================================
In short, the structure of try is used to protect abnormal operations. If an exception occurs between try...except, the operation between except...end will be executed. When designing the try command, you must pay attention to the rationality of the architecture.
4. Defrauding one’s own transaction protection
When making database application software, we often need to encounter the following problems: judge the original data and then make corresponding modifications. This problem seems relatively simple, but if you consider that there are other people on the network using the same system, then you have to consider the possibility of accidental changes. My colleague was careless. Although he considered the multi-user issue after my prompting, he still wrote the problematic code:
================================================== ==============================================
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;
================================================== ==============================================
Analysis: I don’t know if you have seen the problem. The data is judged before AdoConnection1.BeginTrans, and then AdoConnection1.Execute is used to change the data. If the data is shared, then during the period after the judgment to before AdoConnection1.BeginTrans, tb1 The data may have changed, and this transaction protection is of no use.
The correct method is that the judgment and modification must be the same data. The following examples show two methods (the difference is that the location where the transaction is started is different):
Code 1 (after using transaction protection, the same data is judged and modified):
================================================== ==============================================
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;
================================================== ==============================================
Code 2 (using exception capture, if the judgment and modification are not the same data, an exception will occur during adsTemp.Post. This is a feature of the ADODataSet object):
================================================== ==============================================
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;