事务和异常易出现的错误
来源:互联网 发布:数据采集仪 编辑:程序博客网 时间:2024/05/11 04:30
1、Exit方法
原以为Exit方法执行后,会马上退出过程,但是真正做了一个例子来测试后,才让我改变了想法。请看下面这
个例子,flag最后被赋值为'C'。
============================================================
var
flag: string;
begin
try
flag := 'A';
Exit;
flag := 'B';
finally
flag := 'C';
end;
flag := 'D';
end;
===========================================================
分析:不论try子句如何结束,finally 子句总是被执行。(多谢ylmg网友)
2、一个能让整个系统停止运作的小问题
在数据库系统设计中,经常使用事务操作来保证数据的完整性,但是设计不当,却容易产生比较大的影响,下面举个例子说明虽然数据完整性保证了,但是可能令到系统完全停止运作:
============================================================
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本身,而是它将程序挂起,需要用户干预后,才继续执行后面的操作;如果用户这时候离开了计算机,或者没有对这些对话框进行确定操作的话,可想而知,整个系统因为这个事务没有结束而通通处于等待状态了。
为了避免这个问题,原则有两个:
(1)、事务启动后,无需用户干预,程序可以自动结束事务;
(2)、在事务里面做时间最短的操作。
3、try...except...end结构
下面举个例子来说明try结构,还是使用事务操作的例子:
有问题的代码:
============================================================
try
...
AdoConnection1.BeginTrans;
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
===========================================================
分析:如果try之后到AdoConnection1.BeginTrans这段代码中出现异常,将跳转到AdoConnection1.RollbackTrans执行,但是AdoConnection1因为出错并没有启动事务,所以AdoConnection1.RollbackTrans执行时出错了。
正确的代码: ============================================================
AdoConnection1.BeginTrans;
try
...
...
AdoConnection1.CommitTrans;
except
AdoConnection1.RollbackTrans;
end;
============================================================
总之,try的架构是用来保护异常的操作的,try...except之间的产生异常都会执行except...end之间的操作,设计try命令时一定要注意架构的合理性。
4、欺骗了自己的事务保护
在做数据库应用软件时,我们经常需要碰到下面的问题:对原有数据进行判断,然后做出相应的修改。这个问题看似比较简单,但是如果考虑到网络上还有别的人在使用同一个系统,那么,你就不的不考虑可能被意外改变的问题了。我的同事比较粗心,虽然在我的提示下考虑了多用户问题,但是他还是写下了有问题的代码:
============================================================
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之前判断数据,然后使用AdoConnection1.Execute改变数据,如果这个数据是共享的,那么在判断之后到AdoConnection1.BeginTrans之前的这段时间里头,tb1的数据可能已经发生了改变,这个事务保护是没有用处的。
正确的方法是判断和修改必须是同一份数据,下面示例了有两个方法(区别在于启动事务的位置不相同):
代码1(使用事务保护以后,判断的和修改的是同一数据):
============================================================
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(使用异常捕捉,假如判断和修改的不是同一份数据,adsTemp.Post时会出现异常,这个是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;
- 事务和异常易出现的错误
- Apache Camel异常事务的实例和分析 -- 多线程事务
- ora-03113 通信通道的文件结束和ORA-07445: 出现异常错误: 核心转储
- 出现“新事务不能登记到指定的事务处理器中”异常的处理
- 异常和错误的区别
- Java的异常和错误
- 【异常和错误】PHP的异常和错误处理【原创】
- 嵌套事务和事务保存点的错误处理
- 嵌套事务和事务保存点的错误处理
- SQL Server的事务和错误处理
- SQL Server的事务和错误处理
- SQL Server的事务和错误处理
- 出现错误提示“新事务不能登记到指定的事务处理器中”
- 事务的异常处理
- Spring管理Hibernate事务出现异常处理
- .net中常出现的错误异常的处理
- android 混淆代码后出现的问题 异常 错误
- Java异常总结(运行期出现的错误)
- react-native 轮播图
- Centos7上安装Jenkins
- 【小制作】WIFI智能窗帘的制作
- 69. Sqrt(x)
- Python官网下载python3.5.0的执行程序无法运行
- 事务和异常易出现的错误
- http协议详解
- 在win10 上安装Oracle出现“INS-13001环境不满足最低要求”解决办法
- visualizing and understanding convolution network论文
- Android的多线程
- 06 溢出攻击原理之汇编分析
- Centos7在虚拟机上扩展卷的大小
- Javascript基础复习(二)
- shell中关于文件的一些常用操作(一)