请教大家关于在存储过程中实现异常处理的方法 --by 萧月禾(300分)

  • 主题发起人 主题发起人 萧月禾
  • 开始时间 开始时间

萧月禾

Unregistered / Unconfirmed
GUEST, unregistred user!
在Delphi中,利用Try...Except或Try...Finally可以很方便地对程序代码进行异常处理,
当程序出错时自动跳转执行Except或Finally后的代码。而在Sql的存储过程中,
似乎未提供类似的内容。
在存储过程中,通常是通过判断@@Errors的值(为0表示正确)来知道上一个执行结果
是否发生了错误,这样有着其不便的地方。
1、@@Errors是表示其上一个操作结果的错误
如:
Insert ...
print @@Errors --表示Insert操作的错误
Delete...
print @@Errors --表示Delete操作的错误

则不能在一系列的操作后,根据@@Errors判断当中有无发生错误
于是采用2种方法:
第一是用一布尔变量,初值为False,在每条操作语句后,判断当前@@Errors的值,
如果@@Errors不等于0,则给其赋值True,否则不更改其值,最后判断这个变量,
如果为True,则表示以上操作中曾发生过错误。然后给予提示或事务回滚。
第二是采用Goto的方法,在每条操作语句后,判断当前@@Errors的值,
如果@@Errors不等于0,则Goto到(sql)程序的最后。然后给予提示或事务回滚。

感觉这2种方式都不太好,不知道大家有没有更好的方法。
这还是直接在Sql中执行的,如果是在Delphi中调用这个存储过程,则引出下一个问题......

2、系统错误立即响应
如:
Insert ...
if ( @@Errors <> 0 )
raiseerror('发生错误...')
原本是向在Insert操作发生错误的时候,返回自定义提示,
然如果该存储过程是在Delphi或其他开发工具的程序中调用,
则在执行Insert时一旦发生错误,立即响应系统错误,
不会执行下一句,即raiseerror完全不起作用。
请问有没有办法自己控制异常的响应?或者sql中有没有这样的一个开关,
可以设置sql执行中发生错误不自动响应,
而是自己在程序中根据@@Error的值做相应的判断和处理?

这些问题主要针对Sql Server2000

或者大家平时在前台程序中嵌套调用存储过程的时候对错误处理有没有比较好的办法?
还望各位指点一二!

(当然,也可以直接在Delphi程序中做异常处理,但如果要做相应的修改,
则需要重新给客户安装一个个程序,直接在存储过程中做比较方便。
另外,如果不是必要,也不打算使用三层结构。)



 
raiseerror('发生错误...')
应写为RaisError('发生错误...')吧
 
REATE Procedure ProcFCreateNewCDoc
(
@DocCode char(40),
@DocName char(40),
@CommitDate datetime,
@ProjectID int,


@CorrectiveMothed text,
@CorrMethodEfficiency text,
@CorrectiveFee text,
@ParentDocID int
)
As
Set nocount on
Declare @FDocumentID int
Declare @Version int
Declare @DocState smallint--缺省为工作即1,
select @DocState=1
begin tran
if exists(select * from FTabFDocument where DocCode=@DocCode and ProjectID=@ProjectID )
begin
rollback tran
return -10---一个项目中报告编号重复
end

--是第三种报告 所以应修改所有该报告成备份状态
UPDATE ViwFDocCorrectiveDoc SET DocState = 0 --备份状态
WHERE ProjectID =@ProjectID
if @@error<>0
begin
rollback tran
return -20--更改版本状态出错
end


INSERT INTO FTabFDocument (DocCode,DocName,CommitDate,DocState,ProjectID)
Values (@DocCode,@DocName,@CommitDate,@DocState,@ProjectID)
if @@error<>0
begin
rollback tran
return -30--插入FTabFDocument出错
end
select @FDocumentID=@@identity

--插入父子关系
INSERT INTO FTabDocumentHierchy (ParentDocID,ChildDocID)
Values (@ParentDocID, @FDocumentID)
if @@error<>0
begin
rollback tran
return -40---插入父子关系出错
end
--
--确定版本号
if exists(select Version from ViwFDocCorrectiveDoc where ProjectID= @ProjectID)-- ViwFDocReportDoc视图
select @Version=max(Version)+1 from ViwFDocCorrectiveDoc where ProjectID= @ProjectID --最大查出版本号
else
select @Version=1 -- 第一个版本
if @@error<>0
begin
rollback tran
return 50 -- 版本出错
end

INSERT INTO FTabCorrectiveDoc(FDocumentID,CorrectiveMothed,CorrMethodEfficiency,CorrectiveFee,Version)
Values (@FDocumentID,@CorrectiveMothed,@CorrMethodEfficiency,@CorrectiveFee,@Version)
if @@error<>0
begin
rollback tran
return -60 --插入FTabCorrectiveDoc出错
end
else
begin
commit tran
return @FDocumentID
end
GO
 
据我所知, SQL SERVER现并未能实现捕捉的功能,所以很难用DELPHI的错误处理方法.
对此类问题的解决就是我们大家的共愿, 而且RAISERROR也不一定能将错误返回到CLIENT,
你不防在一PROCDURE中多写几个SELECT,INSERT, UPDATE之类的DML东东, 再写一个RAISERROR
不要给条件, 就是要它跑, 有SQL 查寻分析器正常, 但用DELPHI高调就很可能(或是一定)
没戏, 所以就算有TRY又有何用?????
如果你是用ADO高调的话就让DELPHI来做这件事吧!

======================================
VAR
ADOERROR: ERROR;
ADOERRORS: ERRORS;
I: INTEGER;
BEGIN
ADOERRORS := ADOCONNECTION.ERRORS;
TRY
ADOQUERY; //(OR OTHERS ADO DATASET)
EXCEPT
FOR I:=0 TO ADOERRORS.COUNT-1 DO
ADOERROR := ADOERRORS;
CASE ADOERROR.NA????? {I FORGET SORRY} OF
XXXX: BEGIN END;
XXXX: BEGIN END;
ESLE: BEGIN END;
EDN;
EDN;
EDN;
=====================================

很笨吧? 没办法, 你们有好的法了别望了分享!!!!!!!!!!!
 
to weekboy: 不好意思,笔误!

to ugvanxk:你的方法是每次操作前都判断是否可能出错,这个办法我也用过,但感觉并
不是那么好。首先每一步操作前都要进行查询判断,对程序员来说工作量大,同时有些错
误的发生的可能也无法预计;其次,运行效率降低。

to netup:你的方法是通过在前台捕获错误的原生错误码来进行错误分析,这种方式我之
前一直使用,同时写了个通用的错误处理函数统一处理。但现在打算把数据处理的重心放
在后台执行,所以必须用存储过程,错误处理也要放在后台。


请大家继续给予意见罢,甚谢![:)]
 
土豆你还没死啊,怎么好久没见你上qq了,为什么 ????有写问题请教,能不能加我,用你常上的哪个31481622
 
后台象DLEPHI一样排错, 就现在而言, 没办法!!
我在上说的问题你没有??? RAISERROR一定能返回ERROR TO CLIENT???? YOU TYR IT AGAIN
 
>>台象DLEPHI一样排错, 就现在而言, 没办法!!
>> 我在上说的问题你没有??? RAISERROR一定能返回ERROR TO CLIENT???? YOU TYR IT AGAIN
我用的SQL7,感觉就捕捉不到RAISERROR。
 
to ty_unix:
你一直在我qq上呀,我又没删。
不过我已经很少用qq了
有事发email给我罢[:)]
 
kao
土豆老是问这种问题,有没有搞错
 
to yxyyyy: 你要能解决这300分就是你的,不够另开帖子再加[:)]
 
既然T-SQL不象PL/SQL一样有exception的机制,那可能完全在存储过程处理错误是行不通了
只能用与客户端结合的方式。
先不考虑升级的问题,因为不管是什么应用,你都可以做到客户端自动升级的。
客户端错误处理模块应该是一个比较独立的东西,而且它不应该跟后台存储过程紧密结合,
也就是说后台存储过程改了,前台的错误处理模块也不用更改。而这一个目的应该来说是比
较容易实现的,尽量采用代码数据化的处理方式,也就是说,错误处理的代码不直接与具体
的错误相关,而是与一个预先定义好的方式(如后台的一个错误对照表)结合。这样就可以
做到很灵活了。
 
踢一下。
 
>客户端错误处理模块应该是一个比较独立的东西,而且它不应该跟后台存储过程紧密结合
在前台已经可以做到了,但想转移到后台。。。看来还不行,唉[:(]
 
有一个办法
叫你的客户使用Oracle!
哈哈
 
客户端错误处理模块应该是一个比较独立的东西,而且它不应该跟后台存储过程紧密结合
在前台已经可以做到了,但想转移到后台。。。看来还不行,唉[:(]
楼顶的, 能不能详细说下。
非常感谢。
 
同意xianjun
有什么事情在QQ上聊天吧
满意吧?
 
后退
顶部