Що означають різні рівні тяжкості RAISERROR?


74

Моїм найкращим результатом Google було таке :

  • нижче 11 - попередження, а не помилки
  • 11-16 доступні для використання
  • вище 16 - це системні помилки
  • немає різниці в поведінці серед 11-16

Але, з BOL, "Рівень важкості від 0 до 18 може вказати будь-який користувач".

У моїй конкретній збереженій процедурі я хочу, щоб помилка була повернута до клієнтської програми .Net, тому, схоже, будь-який рівень серйозності між 11-18 міг би зробити це. Хтось має якусь достовірну інформацію про те, що означає кожен з рівнів, і як їх слід використовувати?


2
Я не знаю для інших версій, але я був дуже здивований, побачивши, що з SQL Server 2008 серйозність 16 НЕ припиняє виконання.

Я використовую той же трюк для програми Delphi, після спроб і помилок я використовую рівень = 13. Таким чином, виконання не зупиняється (я піднімаю помилку в тригері для відображення інформації про користувача), і користувач отримує повідомлення. Звичайно, це "жахлива погана практика", але ефективна.
LaBracca

"Жахливі погані практики" необхідні, щоб обійти багато-багато-багато перешкод з боку держави-члена. Однак подолання перешкод для РС, як правило, є "гарною практикою".
інженер, що

Відповіді:


107

Рівні важкості механізму баз даних

Ви повинні повернути 16. Чи є за замовчуванням найбільш часто використовуваний рівень помилки:

Вказує на загальні помилки, які користувач може виправити.

Не повертайте 17-18, це вказує на більш серйозні помилки, наприклад, проблеми з ресурсами:

Вкажіть помилки програмного забезпечення, які користувач не може виправити. Повідомте про проблему системному адміністратору.

Також не повертайте 11-15, оскільки вони мають спеціальне значення, прикріплене до кожного рівня (14 - захисний доступ, 15 - синтаксична помилка, 13 - глухий кут тощо).

Рівень 16 не припиняє виконання.

Якщо ви маєте намір зареєструвати попередження, але продовжувати виконувати, використовуйте натомість рівень важкості нижче 10.


Посилання MSDN начебто все говорить - інформація була саме там, у BOL, і я ніколи раніше її не бачив. Дякую!
Steve S.

1
Коли ви говорите "за замовчуванням", ви маєте на увазі, що буде використано рівень помилки 16, якщо я зателефоную в RAISERROR, не передаючи жодних параметрів. тобто він буде зловлений блоком catch?
Трійко

3
Рівень 16 не припиняє виконання. Див. Stackoverflow.com/questions/76346/… . Якщо я чогось не пропустив, можливо, ви захочете оновити свою відповідь.
mcNux

Помилка порушення зовнішнього ключа також має серйозність 16. Інші помилки цілісності даних також можуть мати таку ступінь серйозності, я не знаю, але якщо ви піднімаєте та обробляєте помилки "ділових правил", 16 може ввести в оману. У моєму випадку я в кінцевому підсумку використовував параметри для успіху (істинно чи хибно) та повідомлення про помилку.
Рафаель

1
@mcNux Абсолютно правий, рівень 16 не припиняє виконання, щойно перевірене як на SQL Server 2008 R2, так і на SQL Server 2012. Відновлено редагування .
user692942

7

Рівень тяжкості 16 може припинити виконання.

ПОПРОБУЙТЕ УЛОВКИ з RAISERROR ():

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.

Здивований? Так само, як і я.
Те, що мене також закинуло, не всі тяжкості 16 -ти однакові.
Якби ви прокоментували лінію Divide-By-Zero у самому верху, тоді нічого під нею не працюватиме.
Логіка Divide-By-Zero також генерує виняток важкості- 16 ,
  але вона обробляється з повною зупинкою , на відміну від випадків, коли це відбувається RAISERROR().

Примітка: Використовуйте ;THROWяк останній рядок у блоці Catch-Block, щоб правильно
           викинути виняток SQL для RAISERROR()події, ініційованої вашим Try-Block.
           Це фактично зупинить виконання з повною зупинкою. Кома потрібна , коли інші лінії існують в улові-Block перед викликом . Якщо ваша логіка правильно обробляє помилку в блоці Catch-Block (і ви хотіли б продовжувати обробку   решти логіки після неї), тоді не використовуйте .
;;THROW

;THROW

Висновок:

Не поєднуйте серйозність- 16, вироблену SQL-Server-Engine,
  з такою, яку ви піднімаєте самостійно RAISERROR().
Для всіх намірів і цілей (при навмисному викиданні власних помилок) враховуйте лише 2 серйозності:
    0 (для інформаційного або попереджувального) та
  16 (для кидання винятку, який обробляється в рамках блоку спроб - щоб викинути його на блок блокування) .

Інформація зараз!

Примітка: Якщо ви використовуєте 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, ви ніколи не знаєте , коли може з'явитися ваші інформаційні повідомлення.
Вони можуть з’являтися з перервами протягом всієї партії або відразу, коли партія завершується.


Не закінчується на Sql 2016 навіть з@divideByZero
Майк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.