从存储过程返回错误消息
Posted
技术标签:
【中文标题】从存储过程返回错误消息【英文标题】:Return error message from stored procedure 【发布时间】:2016-01-21 12:38:23 【问题描述】:问题应该很简单,但我不知道答案,也不知道为什么我的存储过程不工作。
CREATE PROCEDURE spTest_Delete
@ID int
AS
begin tran
declare @err int
declare @errMesage nvarchar(max)
set @errMesage = ''
set @err = 0
delete from Test
where ID = @ID
set @err = @@ERROR
set @errMesage = ERROR_MESSAGE()
if @err = 0
commit tran
else
begin
RAISERROR(N'Could not delete !Error nr: %d. Message: %s', 1, 16, @err, @errMesage)
rollback tran
end
此过程运行正常,但在 delete
语句上存在 FK 约束的情况下,它会遇到错误(这很好),我想捕获该错误。
消息 547,级别 16,状态 0,过程 spTest_Delete,第 12 行 DELETE 语句与 REFERENCE 约束冲突 “FK_TEstFK_Test”。数据库“Test”中发生冲突,表 “dbo.Test”,“ID”列。该语句已终止。
无法删除! 错误编号:547。消息:(空)消息 50000,级别 1,状态 16
我的消息变量总是为 null,即使 delete
语句引发错误。
【问题讨论】:
【参考方案1】:尝试使用 TRY CATCH 并像这样捕获您的错误:
BEGIN TRY
delete from Test
where ID = @ID
END TRY
BEGIN CATCH
SET @ErrorMessage = ERROR_MESSAGE()
SET @ErrorSeverity = ERROR_SEVERITY()
SET @ErrorState = ERROR_STATE()
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
BREAK
END CATCH
【讨论】:
Try catch 成功了,但我还是有点困惑,为什么没有 try catch 就不行。 @CiucaS:- 通常建议使用 TRY..CATCH 来捕获错误。你可以尝试使用if ISNULL(@err,0) = 0
.net端如何捕获ErrorMessage?
我看到RaiseError
将返回(通过.NET 异常)它的msg_str
参数如果调用者是.NET 应用程序,但它如何返回它,如果调用者是另一个存储过程? Error_Message
(以及所有 Error_*
函数)在 Exec
之后立即返回 Null
,该存储过程在它之前调用 RaiseError
return
-ed 并且它也不会触发 Catch
在调用存储过程中阻塞。
@Tom 我很想知道你的评论的答案【参考方案2】:
您可能希望开始在您的程序中使用TRY..CATCH 块
为 Transact-SQL 实现错误处理,类似于 Microsoft Visual C# 和 Microsoft Visual C++ 中的异常处理 语言。一组 Transact-SQL 语句可以包含在 TRY 中 堵塞。如果 TRY 块中发生错误,则将控制权传递给 包含在 CATCH 块中的另一组语句。
所以你的程序可以重写为:
CREATE PROCEDURE spTest_Delete @ID INT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION
DELETE
FROM Test
WHERE ID = @ID;
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH
END
另外,请注意您是作为单个删除语句运行的。这意味着它不需要包含在事务中。 This 问题解释了原因。
你的代码变成这样:
CREATE PROCEDURE spTest_Delete @ID INT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
DELETE
FROM Test
WHERE ID = @ID;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH
END
现在为什么你的@errMessage
总是为NULL?因为ERROR_MESSAGE()
仅在捕获块中有效。写在documentation:
返回导致 CATCH 块的错误的消息文本 TRY…CATCH 构造被运行。
Using TRY..CATCH in Transact-SQL 告诉这个:
使用这些函数从任何地方检索错误信息 在 TRY…CATCH 构造的 CATCH 块的范围内。 错误 如果在 CATCH 范围之外调用,函数将返回 NULL 阻止。
【讨论】:
以上是关于从存储过程返回错误消息的主要内容,如果未能解决你的问题,请参考以下文章
Oracle存储过程OUT CLOB返回错误字符串缓冲区太小