Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2005 在T-SQL中尝试CATCH块_Sql Server 2005_Error Handling - Fatal编程技术网

Sql server 2005 在T-SQL中尝试CATCH块

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()

我遇到一个存储过程,该存储过程在尝试更新后立即出现以下错误处理块。以下是SP的最后几行

这样做有什么好处吗?在我看来,这段代码似乎只是重新引用了它捕获的相同错误,而没有添加任何值,如果Try块被完全复制,那么代码的行为可能会100%相同

如果安装了TRY块,结果SP的行为是否会有任何差异

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()返回的字符串中。为了混淆这一点,你必须用你自己的不太详细的错误消息来替换它,而这个例程没有这样做。我没有仔细阅读,并假设任何这样做的人都会捕获并跟踪实际的错误号。