不同的RAISERROR严重性级别是什么意思?


74

我最好的google结果是这样的

  • 低于11的警告而非错误
  • 11-16可使用
  • 16以上是系统错误
  • 11-16岁之间没有行为差异

但是,从BOL开始,“任何用户都可以指定0到18的严重级别。”

在我特定的存储过程中,我希望错误返回给.Net客户端应用程序,因此看起来11-18之间的任何严重性级别都可以解决问题。是否有人掌握有关每个级别的含义以及如何使用的权威信息?


2
我不知道其他版本,但令我感到非常惊讶的是,对于SQL Server 2008,严重性16不会终止执行。

我在Delphi应用程序中使用了相同的技巧,在反复试验后,我使用级别=13。这样就不会停止执行(我在触发器中显示错误以向用户显示信息),并且用户得到了消息。当然,这是“可怕的不良做法”,但有效。
LaBracca

要避免许多许多MS障碍,必须采取“可怕的不良做法”。但是,绕开MS障碍通常是一种“好的做法”。
逆向工程师,

Answers:


107

数据库引擎严重性级别

您应该返回16。这是默认的,最常用的错误级别:

表示可由用户纠正的常规错误。

不要返回17-18,这些错误表示更严重的错误,例如资源问题:

指示用户无法纠正的软件错误。通知您的系统管理员该问题。

也不要返回11-15,因为每个级别都有特殊含义(14-安全访问,15-语法错误,13-死锁等)。

16级不会终止执行。

如果您打算记录警告但继续执行,请使用低于10的严重性级别。


MSDN链接说明了一切-信息就在BOL中,而我之前从未见过。谢谢!
Steve S.

1
当您说“默认”时,是否表示如果我不带任何参数调用RAISERROR,则将使用错误级别16。即它将被一个捕获块捕获?
Triynko

3
第16级不会终止执行。参见stackoverflow.com/questions/76346/…。除非我错过任何事情,否则您可能要更新您的答案。
mcNux

我不知道,外键违反错误的严重性也为16。我不知道其他数据完整性错误也可能具有这种严重性,但是如果您提出和处理“业务规则”错误,则16可能会引起误解。以我为例,我最终使用了成功或失败消息(错误消息)。
拉斐尔

1
@mcNux是绝对正确的,16级也不会终止执行,只是在两个SQL Server 2008 R2和SQL Server 2012的测试已回滚编辑
Lankymart 2015年

7

严重级别16 可以终止执行。

使用RAISERROR()的TRY-CATCH警告:

RAISERROR()严重性为16时,将终止违规行以下所有内容的执行。
但是,适用于“尝试块”内部。

--DECLARE @DivideByZero Int = 1/0--Uncommenting this will Skip everything below.
RAISERROR (N'Before Try: Raise-Error 16.', 16, 0)--Works.
SELECT 'Before Try: Select.'[Marker]--Works.
BEGIN TRY
    RAISERROR (N'Inside Try: Raise-Error 16.', 16, 0)--Not displayed,but sends to Catch-Block.
    SELECT 'Inside Try: Select.'[Marker]--Skipped.
END TRY
BEGIN CATCH
    RAISERROR (N'Inside Catch: Raise-Error 16.', 16, 0)--Works.
    SELECT 'Inside Catch: Select.'[Marker]--Works.
    --RETURN --Adding Return will only skip what is After the Catch-Block for this scope only.
    --;THROW--Shows the RAISERROR() from the Try-Block and Halts Execution. Must include ";".
END CATCH
RAISERROR (N'After Try-Catch: Raise-Error 16.', 16, 0)--Works.
SELECT 'After Try-Catch: Select.'[Marker]--Works.

惊讶吗
我也是如此。引发我困扰的并不是Severity- 16都一样。
如果您要取消最顶部的Divide-By-Zero线的注释,则下面的任何内容都不会运行。
Divide-By-Zero逻辑将生成Severity- 16异常,
  它用句号来处理,这与用抛出时不同RAISERROR()

注:使用;THROW作为最后你钓到的鱼,阻止内线正确
           抛出SQL异常为RAISERROR()你的尝试,阻止触发事件。
           这将有效地停止执行。
           如果;在调用之前在捕获块中存在其他行,则需要使用分号;THROW
如果你的逻辑正确处理在catch块中的错误(你想继续处理
  后的逻辑的其余部分),那么就不能使用;THROW

结论:

不要将SQL-Server-Engine抛出的Severity- 16
  与您使用引发的Severity- 16混淆RAISERROR()
对于所有意图和目的(故意抛出自己的错误),仅考虑2个严重性:
    0(针对信息性或警告)和
  16(针对在Try-Block中处理的异常-将其踢出Catch-Block) 。

现在的信息!

注意:如果RAISERROR()用于显示参考消息,
           则建议使用WITH NOWAIT

RAISERROR('Read me right now!', 0, 1) WITH NOWAIT
RAISERROR('Read me whenever.' , 0, 1)
DECLARE @WaitSeconds Int = 10
DECLARE @WaitFor DateTime = DATEADD(SECOND, @WaitSeconds, 0)
WAITFOR DELAY @WaitFor

当您希望了解
  在整个批次中达到某些里程碑标记时事情进展的情况时,这在长时间批次操作中特别有用。
如果使用WITH NOWAIT,您可能永远不知道信息性消息何时出现。
它们可能在整个批处理过程中间歇出现,或者在批处理完成时一次全部出现。


即使使用@divideByZero
Mike
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.