怎样拦截数据库操作的异常?

bubble 2000-04-04 03:06:00
数据库软件在应用的过程中,有时可能会发生操作异常,而这些异常有可能是在软件开发过程中预料不到的。
如用Delphi编制的数据库程序在执行时需要用到BDE,当该软件只是拷贝到某台机器上并运行后(正确的方法是安装),程序检查到没有BDE后会有提示,怎样才能拦截这些消息呢?
请各位大侠指教。
...全文
580 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
skt985 2001-06-01
  • 打赏
  • 举报
回复
6236关注!
eaglet 2000-04-05
  • 打赏
  • 举报
回复
用try ..except .当程序不处于调试态时,
操作数据库错误不会弹出提示框.
截获错误用 ON EXCEPTION
例如
with query1 do
begin
....
close ;
sql.clear ;
sql.add('insert into tb values(0,0)');

try
execute ;

except
....
on E: Exception do //截获错误
begin
ErrMessage := E.Message ;
if Pos('PRIMARY KEY',ErrMessage) <> 0 then
{如果是主键重复}
begin
ProcError(ERR_PRIMARYKEY) ;
end
else
begin
{如果其它错误}
ProcError(ERR_OTHERERROR) ;
end ;
end ;
end ;

end ;
patpat 2000-04-04
  • 打赏
  • 举报
回复
处理数据库的异常

孙立

用Delphi开发数据库系统时,一定会遇到与数据库配合的问题,最基本的一个问题就是怎样处理数据库约束(constraint)产生的错误。如果用户录入的数据违反约束,数据库会产生类似“Violation of PRIMARY KEY constraint 'PK__table1__07F6335A'. Cannot insert duplicate key in object 'table1'. The statement has been terminated.”这样含混的提示,而用户真正希望看到的是“商品已经存在,您输入的编号重复,请重新输入。”这样的提示,怎样才能把数据库的异常转换为用户可以理解的错误提示呢?这是一个非常常见的问题,但令人遗憾的是在用户手册和流行的参考资料中都找不到直接答案,所以很多开发人员使用了一些令人哭笑不得的办法。比如不创建主键(primary key),而是在每次插入数据之前先查询是否存在相同的数据。又比如不创建外键(foreign key),靠额外的查询来检查数据是否冲突。姑且不论这样做程序代码会有多么臃肿,仅从理论上就可以推论出这是违反并发控制原理的,在你查询和插入之间其它用户完全可能改变了数据库,也就是说用提前查询的办法来代替约束只解决99%的问题,而且随着并发用户的增加,这个百分比还会下降。因此,并发情况下只能依靠数据库约束检查数据,那么Delphi这边怎样做才能替换数据库的错误提示呢?

Delphi的语言称为Object Pascal,它是一种纯粹的面向对象的语言,除了封装、继承、多态这些标准的OO特性,也包括了异常(exception)的概念。在C语言中,大家曾经争论该不该用goto语句,最终结论是goto只适合用在错误处理的地方。如果不使用goto打破调用顺序而用函数返回值表示成功与否,一旦调用嵌套超过3层程序代码就会充满if,代码质量反而下降。好在现在我们有了异常,用它做错误处理就可以把goto彻底赶跑了。关于异常的详细解释请参考用户手册的相关部分,这里要特别指出的是在VCL里面已经贯彻了异常处理,使用VCL就必须使用异常。

回到数据库的话题,程序插入重复数据时,在屏幕上出现“Violation of PRIMARY KEY ...”之前,VCL里面都发生了什么事呢?首先,在Post或者ExecSQL以后,VCL将调用BDE执行SQL,并取得数据库返回的结果代码。如果数据库发现新数据违反约束,会返回错误代码和错误提示,由于不同的数据库规定了不同的错误代码,VCL会针对数据库的类型把原始错误代码转换为BDE统一规定的代码,然后生成一个叫做EDBEngineError的异常,其中包括BDE错误代码、数据库原始错误代码和数据库错误提示。这个异常将中断Post/ExecSQL,如果Post/ExecSQL处于try...except保护之中,程序会跳到except部分寻找相应的处理分支。如果没有try...except或者except中没有对应的处理分支,异常会中断当前的过程/函数,跳回到上级调用者。如果各级程序都没有try...except,那么最终VCL会替你处理,弹出大家熟悉的错误对话框,里面显示数据库的原始错误提示。

知道了VCL处理数据库异常的流程,我们可以看出只要捕捉到EDBEngineError异常,分析其中的错误类型,再抛出一个中文内容的异常就可以解决问题了。这里有2个要点:第一什么时候捕捉异常最合适,第二怎样把约束产生的错误提示转换为与业务相关的中文提示。

在VCL里有一个不引人注意的对象TApplication,以前它一直被当作不可见组件,直到Delphi 5才出现在组件板上。TApplication相当于Windows下的WinMain,处理消息循环,调度所有事件。它里面预置了一个try...except异常保护,程序产生的所有异常,如果没有被提前捕捉到都会在这里处理。TApplication还提供了一个事件OnException,专门供程序员处理TApplication捕捉到的异常,所以TApplication. OnException是捕捉数据库异常的最佳地点。

VCL产生的EDBEngineError有一个数组属性Errors,记录了BDE错误代码、数据库原始错误代码和数据库错误提示,其中Errors[0].SubCode保存了BDE错误代码。BDE错误代码声明在“..\DOC\BDE.INT”文件中,其中重要的有:ERRCODE_KEYVIOL、ERRCODE_REQDERR、ERRCODE_FOREIGNKEYERR、ERRCODE_DETAILRECORDEXIST。理论上根据这个代码就可以分辨错误类型,但不同的数据库返回值的精度并不相同,Oracle对所有错误都有单独的代码,SQL Server和InterBase不能指出外键错误的原因。为进一步区分错误类型,对于SQL Server我们还可以分析错误Message,根据其中的关键词分辨外键错误的原因。

还有一点要注意,实际上VCL可能产生2种数据库异常,除了EDBEngineError以外,还有EDatabaseError,他们分属不同的层次,对EDatabaseError也需要做类似的处理。

这里有一套用于SQL Server 6.5的源代码,里面除了有前面提到的问题,还有一些细节,可以查看用户手册的相关章节。

最后一点要注意的是,Delphi 5有TApplicationEvents组件可以直接使用,Delphi 3/4的用户还需要额外加一句“Application.OnException := dmMain.AppException;”。



孙立


Lin 2000-04-04
  • 打赏
  • 举报
回复
1、推荐:联结数据库或者打开表时使用Try...Except...End结构;
2、编写Application的OnException过程;

2,495

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧