当前位置: 首页 > 知识库问答 >
问题:

存储过程Try/Catch中的错误处理

戈宏义
2023-03-14

我需要在我的存储过程中添加错误处理。我相信当只有一个insert语句时,通常不需要使用BEGIN TRAN/COMMIT TRAN。还有使用SET XACT_ABORT,NOCOUNT ON语句的意义是什么。请给出最佳/标准的方法将错误处理添加到下面的SP中。如果出现错误,我还需要在catch段中调用dbo.usp_get_error_info。请建议。

USE [TEST]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[UspSdtSync]
AS
BEGIN

DECLARE                    @return_value INT
                          ,@RetCode INT
                          ,@RunID INT
                          ,@IntraDayID INT

SET                        @RunID = NULL  
SET                        @IntraDayID = NULL

EXEC                       @return_value = [DST].[SD].[STG].[API_GenerateTempView]
                           @SchemaName = N'TEST_A',
                           @ViewName = N'vw_TEST_KB_CGSE',
                           @ColumnList = N'statusE, statusF, statusG, statusH, LastModifiedDate, LastModifiedBy, LastReviewedBy, statusI, statusJ, Email, Mobile, HomePhone, WorkPhone, statusK, statusL, Dob',
                           @OrderByList = NULL,
                           @ResultSet = 1,                           
                           @RunID = @RunID,
                           @IntraDayID = @IntraDayID,
                           @RetCode = @RetCode OUTPUT

MERGE INTO AeoiSdtTemp AS t
USING (SELECT statusE, statusF, statusG, statusH, LastModifiedDate, LastModifiedBy, LastReviewedBy, statusI, statusJ, Email, Mobile, HomePhone, WorkPhone, statusK, statusL, Dob 
FROM [DST].[SD].[TEST_KB_KTA].[vw_SDT_TEST_KB_CGSE_Temp]) AS s ON ( t.statusE = s.statusE) AND (t.statusF = s.statusF) AND (t.statusG = s.statusG) AND (t.statusH = s.statusH)

/*** Insert records directly into local KTA table ***/
WHEN NOT MATCHED THEN
INSERT (statusE, statusF, statusG, statusH, LastModifiedDate, StatusCode, LastModifiedBy, LastReviewedBy, CreatedDate, statusI, statusJ, Email, Mobile, HomePhone, WorkPhone, statusK, statusL, Dob)
VALUES(s.statusE, s.statusF, s.statusG, s.statusH, s.LastModifiedDate, '11', s.LastModifiedBy, s.LastReviewedBy, GETDATE(), s.statusI, s.statusJ, s.Email, s.Mobile, s.HomePhone, s.WorkPhone, s.statusK, s.statusL, s.Dob)

/*** Update records that exist ***/
WHEN MATCHED THEN
UPDATE SET LastModifiedDate = s.LastModifiedDate, LastModifiedBy = s.LastModifiedBy, LastReviewedBy = s.LastReviewedBy, statusI = s.statusI, statusJ = s.statusJ, Email = s.Email, Mobile = s.Mobile, HomePhone = s.HomePhone, WorkPhone = s.WorkPhone, statusK = s.statusK, statusL = s.statusL, Dob = s.Dob;

END
GO

共有1个答案

田骁
2023-03-14

在默认自动提交模式下的单语句存储过程中,不需要启动显式事务,也不需要在上指定<code>SET XACT_ABORT。运行时错误将回滚该语句所做的任何更改,错误将返回到客户端,而无需额外代码。

在多语句过程中(比如您问题中的< code>EXEC和< code>MERGE),显式事务将确保全有或全无行为,允许您在成功时提交事务,或者在出现错误时回滚事务。添加结构化错误处理可确保< code>TRY块中的代码在出错后不会继续运行,并且< code>CATCH块提供了一个集中错误处理的便利位置,通常在需要时回滚事务并重新引发错误。

SET NOCOUNT ON禁止将DONE_IN_PROC(rowcount)消息返回给不需要或不期望它们的客户端。这对于ADO经典(而不是ADO.NET)等需要额外编程来处理这些额外结果的某些API尤其重要。

<code>将XACT_ABORT设置为ON</code>可确保在发生错误或客户端超时后回滚事务。当发生客户端超时时,客户端API会向停止执行查询发送取消请求,以便SQL Server取消批处理时不会执行后续代码,包括CATCH块<在这种情况下,code>SET XACT_ABORT ON将立即回滚事务。

下面是一个结构化错误处理的例子。我没有在这里的catch块中包括调用< code > dbo . USP _ get _ error _ info ,因为我不知道它做什么。< code>THROW将重新引发原始错误。

ALTER PROCEDURE [dbo].[UspSdtSync]
AS
SET NOCOUNT ON; --suppress row count messages if not needed
SET XACT_ABORT ON; --ensure transaction is rolled back immediately after timeout

DECLARE                    @return_value INT
                          ,@RetCode INT
                          ,@RunID INT
                          ,@IntraDayID INT;

SET                        @RunID = NULL;  
SET                        @IntraDayID = NULL;

BEGIN TRAN;

EXEC                       @return_value = [DST].[SD].[STG].[API_GenerateTempView]
                           @SchemaName = N'TEST_A',
                           @ViewName = N'vw_TEST_KB_CGSE',
                           @ColumnList = N'statusE, statusF, statusG, statusH, LastModifiedDate, LastModifiedBy, LastReviewedBy, statusI, statusJ, Email, Mobile, HomePhone, WorkPhone, statusK, statusL, Dob',
                           @OrderByList = NULL,
                           @ResultSet = 1,                           
                           @RunID = @RunID,
                           @IntraDayID = @IntraDayID,
                           @RetCode = @RetCode OUTPUT;

MERGE INTO AeoiSdtTemp AS t
USING (SELECT statusE, statusF, statusG, statusH, LastModifiedDate, LastModifiedBy, LastReviewedBy, statusI, statusJ, Email, Mobile, HomePhone, WorkPhone, statusK, statusL, Dob 
FROM [DST].[SD].[TEST_KB_KTA].[vw_SDT_TEST_KB_CGSE_Temp]) AS s ON ( t.statusE = s.statusE) AND (t.statusF = s.statusF) AND (t.statusG = s.statusG) AND (t.statusH = s.statusH)

/*** Insert records directly into local KTA table ***/
WHEN NOT MATCHED THEN
INSERT (statusE, statusF, statusG, statusH, LastModifiedDate, StatusCode, LastModifiedBy, LastReviewedBy, CreatedDate, statusI, statusJ, Email, Mobile, HomePhone, WorkPhone, statusK, statusL, Dob)
VALUES(s.statusE, s.statusF, s.statusG, s.statusH, s.LastModifiedDate, '11', s.LastModifiedBy, s.LastReviewedBy, GETDATE(), s.statusI, s.statusJ, s.Email, s.Mobile, s.HomePhone, s.WorkPhone, s.statusK, s.statusL, s.Dob)

/*** Update records that exist ***/
WHEN MATCHED THEN
UPDATE SET LastModifiedDate = s.LastModifiedDate, LastModifiedBy = s.LastModifiedBy, LastReviewedBy = s.LastReviewedBy, statusI = s.statusI, statusJ = s.statusJ, Email = s.Email, Mobile = s.Mobile, HomePhone = s.HomePhone, WorkPhone = s.WorkPhone, statusK = s.statusK, statusL = s.statusL, Dob = s.Dob;

COMMIT;

END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK; --rollback transaction of needed
    THROW; --re-raise error to client
END CATCH;
GO
 类似资料:
  • 不管你多么精通编程,有时我们的脚本总还是会出现错误。可能是因为我们的编写出错,或是与预期不同的用户输入,或是错误的服务端响应以及其他数千种原因。 通常,如果发生错误,脚本就会“死亡”(立即停止),并在控制台将错误打印出来。 但是有一种语法结构 try..catch,它使我们可以“捕获(catch)”错误,因此脚本可以执行更合理的操作,而不是死掉。 “try…catch” 语法 try..catch

  • 我们在SQL Server存储过程中使用以下错误处理模式: 但是当存储过程中出现以下错误时,try/catch块不起作用。 错误详细信息:存储过程试图将值插入非NULL列。 在执行存储过程中,我得到了以下错误 EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。上一个计数=1,当前计数=0。 msg 3903, Level 16, State 1, Line 30 ROLLB

  • 问题内容: 我相信MySQL当前没有可用的东西允许访问MySQL存储过程中最后执行的语句。这意味着在存储过程中引发泛型时,很难/不可能得出错误的确切性质。 是否有人有变通办法来推导MySQL存储过程中的错误,而不涉及为每个可能的SQLSTATE声明处理程序? 例如,假设我正在尝试返回一个error_status,它超出了下面的通用“ SQLException在此块中的某处发生”: 有小费吗? PS

  • 这个块似乎没有捕获发生的错误,这很奇怪,考虑到我对网站的注册部分有一个类似的块。这将处理登录。该错误发生在第三行 并引发此错误: 当电子邮件格式错误时会发生这种情况,例如。因此,当它是时,我希望在块中设置错误消息。 有人知道为什么这个< code>try catch不起作用吗?

  • 我应该如何在TypeScript中使用Try/Catch?我不希望它检查给定块中的任何错误,因为我已经检查了它们(错误是预期的,状态由catch控制)。 我将代码包装在Try/Catch中(仅为示例): TypeScript拒绝编译它。有没有办法告诉TypeScript我知道这个错误,并且我可以接受?我不想在每一行上都使用忽略(假设我可以有更长的代码),也不想关闭严格模式。有没有更好的解决方案?

  • 我面临着从CSV到MSSQL表的批量插入的问题。使用try, catch块我看不到任何错误,但当我在没有try catch块的情况下执行时,它会给出以下3个错误。 Msg 4864,级别16,状态1,第1行第2行第10列(InActiveDate)的批量加载数据转换错误(指定代码页的类型不匹配或无效字符)。 消息 7399,级别 16,状态 1,第 1 行 链接服务器“(空)”的 OLE DB 提