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;

转载于:https://www.cnblogs.com/yechanglv/p/6923167.html

事务和异常易出现的错误相关推荐

  1. SQL Server 事务、异常和游标

    建议先阅读存储过程:SQL Server 存储过程 Ø 事务 在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整体要么全部成功,要么全部失败,这就需要用到事务. 1. 事务的特点 事务有若 ...

  2. 5个golang中易犯的错误

    点击上方蓝字关注我们 To err is human,to forgive divine. -Alexander Pope 初学golang我们经常会犯一些错误,虽然它们不会产生类型检查的异常,但是它 ...

  3. Android4.0 Design之UI设计易犯的错误2

    想成为Android的杰出开发工程师,不懂得Android的设计规则怎么可以,Android4.0问世后谷歌公司为Android程序员规范了一系列的设计原则,不要再盲目的模仿IOS的设计了,因为And ...

  4. 导出Excel出现“异常来自 HRESULT:0x800A03EC”错误的解决方法(已验证)

    导出Excel出现"异常来自 HRESULT:0x800A03EC"错误的解决方法(已验证) 参考文章: (1)导出Excel出现"异常来自 HRESULT:0x800A ...

  5. 无法启动 MS DTC 事务管理器。LogInit 返回错误 0x2. 怎么办?

    无法启动 MS DTC 事务管理器.LogInit 返回错误 0x2. 怎么办? ----------------------------------------------------------- ...

  6. 安卓软件错误log_Android编程实现捕获程序异常退出时的错误log信息功能详解

    本文实例讲述了Android编程实现捕获程序异常退出时的错误log信息功能.分享给大家供大家参考,具体如下: 很多时候我们程序无缘无故的就挂掉了,让我们一头雾水,如果刚好我们在调试,那我们可以通过错误 ...

  7. css html 对错号,HTML_DIV+CSS编码时易犯的错误,CSS+DIV是网站标准(或称“WEB - phpStudy...

    DIV+CSS编码时易犯的错误 CSS+DIV是网站标准(或称"WEB标准")中常用的术语之一,通常为了说明与HTML网页设计语言中的表格(table)定位方式的区别,因为XHTM ...

  8. 7个跑步易犯的错误和解决办法

    似乎所有人都认为跑步是一种非常简单的锻炼方式,然而,其实不然,跑步涉及到许多专业知识.错误的跑步,不仅影响锻炼效果,而且还容易导致受伤. 1.鞋子不合适 问题:穿着太旧的跑步鞋或者类型不合适的运动鞋容 ...

  9. Linux管理员易犯的错误

    对于初入linux的管理员们来说,迁移到Linux是一场噩梦,而且在Linux管理中稍微不小心就会出错,如果不避免这些错误的话就会给我们的网络和系统带来风险,那么我们现在就去看看Linux管理员易犯的 ...

最新文章

  1. python自动化测试数据驱动_利用Python如何实现数据驱动的接口自动化测试
  2. 分布式开放消息系统(RocketMQ)的原理与实践
  3. VS2013+opencv2.4.9配置步骤详解
  4. 程序员公司选择:创业公司、中等规模公司、大公司
  5. perl 安装GD 出错解决方案
  6. windows无法访问指定设备_恢复 你的电脑/设备需要修改 未连接或无法访问所需设备。...
  7. java 替换所有中文_java 替换中文
  8. linux cxf服务端,Apache CXF 框架应用实战
  9. Win10 IPv6 远程桌面连接(小米路由器)
  10. POI 报错问题:Merged region A15 must contain 2 or more cells
  11. 【练习】Building a Hypermedia-Driven RESTful Web Service
  12. Temporal Abstraction
  13. php办公电脑配置,性能不俗的办公电脑推荐配置 八代奔腾G5400搭配H310电脑配置推荐...
  14. Android Button控件字母大小写显示问题
  15. c#模拟微信运动排行榜
  16. Java LTS版本——Java 11新特性
  17. OSPF prefix-suppression Test
  18. Pytorch 实践 —— 乳腺癌预测
  19. 使用pyechart生成节点关系图
  20. 组队学习可汗学院统计学1

热门文章

  1. java怎么输出liststring_春招|春招实习上岸,分享面筋回报社区(Java、Python)...
  2. cisco 模拟器安装及交换机的基本配置实验心得_看完这份1113页的TCP/IP协议+路由与交换机,成功上岸字节跳动...
  3. java table 内容居中_JTable内容居中显示 | 学步园
  4. java中将查询数据导出_如何在R中将数据框导出到Excel
  5. java字典类_Java字典类
  6. python冒泡循环示例_Python for循环示例
  7. kotlin null_Kotlin Null安全– Kotlin可空
  8. 如何学习Web前端知识转型?
  9. Java面试题:Java设计模式11道常见面试题
  10. Java基础之字符串详细比较