我用的是SQL SERVER 2000 企业版。在一个存储过程中,例如我写了一句INSERT语句,但是由于unique索引的冲突或其它原因可能会导致此INSERT语句执行失败,当然也可能是UPDATE语句。我怎么样捕获这个错误呢?
这个存储过程是在上面的应用(VC,通过ADO(ODBC))调用的。有没有类似try...catch...之类的语句?
我用:
IF @@ERROR<>0
好像不行。另外,如果一个存储过程中有三句INSERT语句,如果第一条INSERT语句因为UNIQUE索引或其它原因导致失败了,下面的两条INSERT会不会继续执行?(也是在VC中通过ODBC调用)。存储过程中最通用的错误处理是怎么个写法?
这个存储过程是在上面的应用(VC,通过ADO(ODBC))调用的。有没有类似try...catch...之类的语句?
我用:
IF @@ERROR<>0
好像不行。另外,如果一个存储过程中有三句INSERT语句,如果第一条INSERT语句因为UNIQUE索引或其它原因导致失败了,下面的两条INSERT会不会继续执行?(也是在VC中通过ODBC调用)。存储过程中最通用的错误处理是怎么个写法?
--下面演示了SQL错误处理的脆弱性
--演示1
--测试的存储过程1
create proc p1
as
print 12/0
if @@error<>0
print '发生错误1'
select * from newid()
if @@error<>0
print '发生错误2'
go
--调用
exec p1
go
--删除测试
drop proc p1
/*--测试结果
服务器: 消息 8134,级别 16,状态 1,过程 p1,行 6
遇到被零除错误。
发生错误1
服务器: 消息 208,级别 16,状态 1,过程 p1,行 10
对象名 'newid' 无效。
--*/
/*--结论1:
错误1,不是严重的错误,所以SQL会执行下去
错误2,属于严重的错误,所以SQL没有执行下去,因为没有第二个print的结果
--*/
--演示2,存储过程嵌套调用中的错误
--测试的存储过程1
create proc p1
as
print 12/0
if @@error<>0
print '发生错误1'
select * from newid()
if @@error<>0
print '发生错误2'
go
--测试的存储过程2
create proc p2
as
exec p1
if @@error<>0
print '调用 存储过程1 异常结束'
else
print '调用 存储过程1 正常结束'
go
--调用
exec p2
go
--删除测试
drop proc p1,p2
/*--测试结果
服务器: 消息 8134,级别 16,状态 1,过程 p1,行 8
遇到被零除错误。
发生错误1
服务器: 消息 208,级别 16,状态 1,过程 p1,行 12
对象名 'newid' 无效。
调用 存储过程1 异常结束
--*/
/*--结论2:
被调用的存储过程发生严重错误时,调用它的存储过程可以捕获错误,并可以继续执行下去
--*/
--演示3,更严重的错误,无法用 set xact_abort on 来自动回滚事务
set xact_abort on --我们希望能自动回滚事务
begin tran
create table #t(id int)
insert #t select 1
select * from newid()
commit tran
go
select * from #t
rollback tran
/*--测试结果
(所影响的行数为 1 行)
服务器: 消息 208,级别 16,状态 1,行 5
对象名 'newid' 无效。
id
-----------
1
(所影响的行数为 1 行)
--*/
/*--结论3:
我们希望 set xact_abort on 可以实现出错时自动回滚事务
但结果令我们希望,出错时,事务并没有被回滚
因为我们查询到了#t的结果,而且最后的回滚语句也并没有报错
--*/
到2005以后有TRY...CATCH 可以捕捉一些异常具体用法类似:
----try...catch用法
begin try
select 1/0
end try
begin catch
print'打印错误'
end catch---raiserror的用法
begin try
raiserror('生成一个错误消息',11,1)
end try
begin catch
select error_message() as 错误消息,
error_severity() as严重级别,
error_state() as state;
end catch---使用sp_addmessage存储过程添加自定义错误
exec sp_addmessage 50001,15, N'new user defined error message!',us_english
exec sp_addmessage 50001,15, N'新增用户自定义错误消息!'
exec sp_dropmessage 50001,'all'---使用sp_altermessage存储过程修改用户定义错误消息
exec sp_altermessage 50001,'with_log',true'
IF @@ERROR=0 是不是永远返回TRUE?
因为据说IF会清空@@ERROR?有没有更好的方法?
if @@Error <>0
begin
roll back tran
select retCode=0
end Insert table2(....) valuse(...)
if @@Error <>0
begin
roll back tran
select retCode=0
end
lz可以考虑改变一下策略,先执行update,判断
if @@rowcount=0
begin
insert into
end
如:
declare @error int
begin tran
begin
update t1 set a=1
set @error=@@error
update t2 set a=2
set @error=@error+@@error
.....
end
if @error=0
commit
else
rollback
有没有更好的呢?一句失败的delete(因为该表的主键在其它表中存在外键关联)之后的语句会不会继续执行,例如IF @@ERROR?
IF (@@ERROR <> 0)
SET @ErrorSave = @@ERROR但是我自己写了一个DELETE,这个DELETE会失败,在DELETE下面我加上:
IF (@@ERROR <> 0)
BEGIN
SET @ErrorSave = @@ERROR
PRINT @ErrorSave
END打印出来的一直是0,看来必须这样:
delete ...
SET @ErrorSave = @@ERROR
IF @ErrorSave <> 0)