如何在sql server中重新抛出相同的异常

Sha*_*pta 79 sql t-sql database sql-server exception-handling

我想在我的try块中出现的sql server中重新抛出相同的异常.我可以抛出相同的消息,但我想抛出相同的错误.

BEGIN TRANSACTION
    BEGIN TRY
            INSERT INTO Tags.tblDomain 
            (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
            COMMIT TRANSACTION
    END TRY

    BEGIN CATCH
            declare @severity int; 
            declare @state int;

            select @severity=error_severity(), @state=error_state();

            RAISERROR(@@Error,@ErrorSeverity,@state);
            ROLLBACK TRANSACTION
    END CATCH
Run Code Online (Sandbox Code Playgroud)

RAISERROR(@@Error, @ErrorSeverity, @state);

这一行会显示错误,但我希望功能类似.这会引发错误,错误编号为50000,但我想要抛出错误的数字,我正在通过@@error,

我想在前端捕获此错误

catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
Run Code Online (Sandbox Code Playgroud)

我想要这个功能.使用raiseerror无法实现.我不想在后端给出自定义错误消息.

当我通过ErrorNo抛出catch时,RAISEERROR应该返回下面提到的错误

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
Run Code Online (Sandbox Code Playgroud)

第14行违反UNIQUE KEY约束'UK_DomainCode'.无法在对象'Tags.tblDomain'中插入重复键.该语句已终止.

编辑:

如果我希望在前端处理异常,考虑到存储过程包含需要执行的多个查询,那么不使用try catch块的缺点是什么?

Mic*_*ael 124

SQL 2012引入了throw语句:

http://msdn.microsoft.com/en-us/library/ee677615.aspx

如果指定THROW语句没有参数,则它必须出现在CATCH块内.这会导致捕获的异常被引发.

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH
Run Code Online (Sandbox Code Playgroud)

  • `ROLLBACK` 行上的分号很重要!没有它,您可能会收到“SQLException:无法回滚 THROW”。 (5认同)
  • @BogdanBogdanov所以你可以记录错误,可能会处理一些情况,但是如果你不能那么你想重新抛出错误,那么任何更高的try/catch都可以有机会处理它 (3认同)
  • 比旧方式更清洁,更易读. (2认同)
  • 请注意,看起来此解决方案仅适用于sql server 2012及更高版本:https://msdn.microsoft.com/en-us/library/ee677615.aspx (2认同)

Ben*_*pka 106

这是一个功能齐全的干净代码示例,用于在发生错误时回滚一系列语句并报告错误消息.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
Run Code Online (Sandbox Code Playgroud)

  • 我在存储过程中使用它,发现它会在`raiserror`之后继续执行,这与`throw`之后c#退出的方式不同.所以我在`catch`中添加了一个`return`,因为我想匹配那个行为. (8认同)

Rob*_*ley 5

我认为你的选择是:

  • 不要发现错误(让它冒泡)
  • 举一个自定义的

在某些时候,SQL 可能会引入 reraise 命令,或者仅捕获某些错误的能力。但是现在,请使用解决方法。对不起。

  • 在 sql 2012 中,您可以使用新的 THROW 关键字重新引发异常 (8认同)
  • 是的。当然,当问到这个问题时,这是不可用的。 (5认同)

nze*_*min 5

重新引出CATCH块内部(SQL2012之前的代码,对SQL2012及更高版本使用THROW语句):

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
Run Code Online (Sandbox Code Playgroud)