Sql server 2005 在T-SQL中尝试CATCH块
我遇到一个存储过程,该存储过程在尝试更新后立即出现以下错误处理块。以下是SP的最后几行 这样做有什么好处吗?在我看来,这段代码似乎只是重新引用了它捕获的相同错误,而没有添加任何值,如果Try块被完全复制,那么代码的行为可能会100%相同 如果安装了TRY块,结果SP的行为是否会有任何差异Sql server 2005 在T-SQL中尝试CATCH块,sql-server-2005,error-handling,Sql Server 2005,Error Handling,我遇到一个存储过程,该存储过程在尝试更新后立即出现以下错误处理块。以下是SP的最后几行 这样做有什么好处吗?在我看来,这段代码似乎只是重新引用了它捕获的相同错误,而没有添加任何值,如果Try块被完全复制,那么代码的行为可能会100%相同 如果安装了TRY块,结果SP的行为是否会有任何差异 BEGIN CATCH SELECT @ErrMsg = ERROR_MESSAGE(), @ErrSev = ERROR_SEVERITY(), @ErrState = ERROR_STATE()
BEGIN CATCH
SELECT @ErrMsg = ERROR_MESSAGE(), @ErrSev = ERROR_SEVERITY(), @ErrState = ERROR_STATE()
RAISERROR (@ErrMsg, @ErrSev, @ErrState)
END CATCH
我们通常在存储过程中这样编写catch块
BEGIN CATCH
DECLARE @i_intErrorNo int
DECLARE @i_strErrorMsg nvarchar(1000)
DECLARE @i_strErrorProc nvarchar(1000)
DECLARE @i_intErrorLine int
SELECT @i_intErrorNo=Error_Number()
SELECT @i_strErrorMsg=Error_Message()
SELECT @i_strErrorProc=Error_Procedure()
SELECT @i_intErrorLine=Error_Line()
INSERT INTO error table ////// Insert statement.
END CATCH
这是我们用来存储错误的方法。为了向用户发送正确的消息,我始终使用存储过程的输出参数来显示错误的详细/必需原因。如果查看,则会看到以下一般说明:
生成错误消息并
启动服务器的错误处理
一场错误可以是
引用用户定义的消息
存储在sys.messages目录中
动态查看或生成消息。
该消息作为服务器返回
发送给调用方的错误消息
应用程序或关联的捕获
TRY…CATCH构造的块
“调用应用程序”似乎会收到错误消息。存储过程的创建者可能只希望报告错误消息、严重性和状态,而不希望添加其他选项。这可能是出于安全考虑,或者只是调用应用程序不需要知道额外的信息(可能是详细的或过于详细的)。除非返回的任何消息的“行错误发生”部分引用的是RAISERROR行,而不是实际发生错误的行,没有区别。正如@Chris所说,这样做的主要原因是允许您以编程方式使用/操作错误数据。有一个细微的区别,如下所示 首先设置以下各项:
CREATE TABLE TMP
( ROW_ID int NOT NULL,
ALTER TABLE TMP ADD CONSTRAINT PK_TMP PRIMARY KEY CLUSTERED (ROW_ID)
)
GO
CREATE PROC pTMP1
AS
BEGIN TRY
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(2)
END TRY
BEGIN CATCH
DECLARE @ErrMsg varchar(max)= ERROR_MESSAGE(),
@ErrSev int = ERROR_SEVERITY(),
@ErrState int = ERROR_STATE()
RAISERROR (@ErrMsg, @ErrSev, @ErrState)
END CATCH
GO
CREATE PROC pTMP2
AS
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(2)
GO
SET NOCOUNT ON
DELETE TMP
exec pTMP1
SELECT * FROM TMP
DELETE TMP
exec pTMP2
SELECT * FROM TMP
SET NOCOUNT OFF
--Cleanup
DROP PROCEDURE pTMP1
DROP PROCEDURE pTMP2
DROP TABLE TMP
现在运行以下命令:
CREATE TABLE TMP
( ROW_ID int NOT NULL,
ALTER TABLE TMP ADD CONSTRAINT PK_TMP PRIMARY KEY CLUSTERED (ROW_ID)
)
GO
CREATE PROC pTMP1
AS
BEGIN TRY
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(2)
END TRY
BEGIN CATCH
DECLARE @ErrMsg varchar(max)= ERROR_MESSAGE(),
@ErrSev int = ERROR_SEVERITY(),
@ErrState int = ERROR_STATE()
RAISERROR (@ErrMsg, @ErrSev, @ErrState)
END CATCH
GO
CREATE PROC pTMP2
AS
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(1)
INSERT INTO TMP VALUES(2)
GO
SET NOCOUNT ON
DELETE TMP
exec pTMP1
SELECT * FROM TMP
DELETE TMP
exec pTMP2
SELECT * FROM TMP
SET NOCOUNT OFF
--Cleanup
DROP PROCEDURE pTMP1
DROP PROCEDURE pTMP2
DROP TABLE TMP
您应该得到以下结果:
Msg 50000, Level 14, State 1, Procedure pTMP1, Line 12
Violation of PRIMARY KEY constraint 'PK_TMP'. Cannot insert duplicate key in object 'dbo.TMP'. The duplicate key value is (1).
ROW_ID
-----------
1
Msg 2627, Level 14, State 1, Procedure pTMP2, Line 4
Violation of PRIMARY KEY constraint 'PK_TMP'. Cannot insert duplicate key in object 'dbo.TMP'. The duplicate key value is (1).
The statement has been terminated.
ROW_ID
-----------
1
2
请注意,TRY..CATCH
版本没有执行第三条INSERT
语句,而pTMP2
proc执行了。这是因为一旦发生错误,控件就会跳转到CATCH
注意:pTMP2
的行为受XACT\u ABORT
设置的影响
结论
使用所演示的TRY..CATCH
的好处取决于您如何管理事务边界
- 如果您回滚任何错误,则更改将撤消。但这并不能消除附加处理等副作用。注意:如果不同的会话同时使用
查询和(NOLOCK)
,它甚至可以观察到临时更改TMP
- 但是,如果您不打算回滚事务,您可能会发现该技术对于防止应用某些数据更改非常重要,尽管之前发生了错误
CATCH
抛出新的异常,因此就我所见,它实际上似乎是减去值……我总是希望在前端有一个自定义错误消息,而不是sql生成的错误信息。这种方式将为您提供逻辑错误和技术错误,您已经理解并提到了这些错误。所有这些“额外信息”都包含在error_MESSAGE()返回的字符串中。为了混淆这一点,你必须用你自己的不太详细的错误消息来替换它,而这个例程没有这样做。我没有仔细阅读,并假设任何这样做的人都会捕获并跟踪实际的错误号。