Реализация обработки ошибок T-SQL

Завершено

Ошибка указывает на проблему или заметную неполадку, возникающую во время операции с базой данных. Ошибки могут создаваться ядром СУБД SQL Server в ответ на событие или сбой на уровне системы; или вы можете создать ошибки приложения в коде Transact-SQL.

Элементы ошибок ядра СУБД

Независимо от причины каждая ошибка состоит из следующих элементов:

  • Номер ошибки — уникальный номер, определяющий конкретную ошибку.
  • Сообщение об ошибке — текст, описывающий ошибку.
  • Серьезность — числовое указание серьезности от 1 до 25.
  • Состояние — внутренний код состояния для условия ядра СУБД.
  • Процедура — имя хранимой процедуры или триггера, в котором произошла ошибка.
  • Номер строки — какая инструкция в пакете или процедуре вызвала ошибку.

Системные ошибки

Системные ошибки предопределяются, и их можно просмотреть в системном представлении sys.messages . При возникновении системной ошибки SQL Server может выполнять автоматическое исправление в зависимости от серьезности ошибки. Например, при возникновении ошибки с высокой серьезностью SQL Server может отключить базу данных или даже остановить службу ядра СУБД.

Пользовательские ошибки

Вы можете создавать ошибки в коде Transact-SQL для реагирования на условия, связанные с приложением, или настраивать сведения, отправленные клиентским приложениям в ответ на системные ошибки. Эти ошибки приложения можно определить непосредственно там, где они создаются, или предопределить в таблице sys.messages вместе с системными ошибками. Номера ошибок, используемые для пользовательских ошибок, должны иметь значение 50001 или больше.

Чтобы добавить настраиваемое сообщение об ошибке в sys.messages, используйте sp_addmessage. Пользователь сообщения должен быть членом предопределенных ролей сервера sysadmin или serveradmin.

Это синтаксис sp_addmessage:

sp_addmessage [ @msgnum= ] msg_id , [ @severity= ] severity , [ @msgtext= ] 'msg' 
     [ , [ @lang= ] 'language' ] 
     [ , [ @with_log= ] { 'TRUE' | 'FALSE' } ] 
     [ , [ @replace= ] 'replace' ]

Ниже приведен пример пользовательского сообщения об ошибке с помощью этого синтаксиса:

sp_addmessage 50001, 10, N’Unexpected value entered’;

Замечание

sp_addmessageподдерживается только в SQL Server. В База данных SQL Azure и Управляемый экземпляр SQL Azure sp_addmessage не поддерживается, поэтому вы не можете ссылаться msg_id на более чем 50000. На этих платформах используйте строку RAISERROR сообщения или THROW в сочетании с FORMATMESSAGE()ней.

Кроме того, можно определить пользовательские сообщения об ошибках. Члены роли сервера sysadmin могут использовать дополнительный параметр @with_log. Если задано значение TRUE, ошибка также будет записана в журнале приложений Windows. Любое сообщение, записанное в журнал приложений Windows, также записывается в журнал ошибок SQL Server. Будьте разумны с использованием @with_log параметра, так как сетевые и системные администраторы, как правило, не любят приложения, которые являются "чатными" в системных журналах. Однако, если ошибка должна быть перехвачена оповещением, её необходимо сначала записать в журнал приложений Windows.

Замечание

Вызов системных ошибок не поддерживается.

Сообщения можно заменить, не удаляя их сначала с помощью @replace параметра = "заменить".

Сообщения настраиваются, и разные могут быть добавлены для одного и того же номера ошибки для нескольких языков на основании значения language_id.

Замечание

Сообщения на английском языке имеют language_id 1033.

Генерация ошибок с помощью RAISERROR

Замечание

RAISERROR не рекомендуется для новой разработки. Используется THROW для нового кода T-SQL. RAISERROR остается полезным для устаревшего кода, для повышения уровня серьезности выше 16 (который THROW не может делать напрямую), а также для printfформатирования динамических сообщений в стиле (современная альтернатива сочетается FORMATMESSAGE() с THROW).

Оба PRINT и RAISERROR могут использоваться для возврата сведений или предупреждений в приложения. RAISERROR позволяет приложениям вызывать ошибку, которая может быть поймана процессом вызова.

RAISERROR

Возможность вызывать ошибки в T-SQL упрощает обработку ошибок в приложении, так как она отправляется как любая другая системная ошибка. RAISERROR используется для:

  • Помощь в устранении проблем с кодом T-SQL.
  • Проверьте значения данных.
  • Возвращайте сообщения, содержащие переменный текст.

Замечание

Использование инструкции PRINT аналогично возникновению ошибки серьезности 10.

Ниже приведен пример пользовательского сообщения об ошибке с помощью RAISERROR.

RAISERROR (N'%s %d', -- Message text,
    10, -- Severity,
    1, -- State,
    N'Custom error message number',
    2)

При активации возвращается:

Custom error message number 2

В предыдущем примере %d является заполнителем для числа и %s является заполнителем строки. Кроме того, следует отметить, что номер сообщения не был указан. При возникновении ошибок со строками сообщений с помощью этого синтаксиса всегда имеется номер ошибки 50000.

Генерация ошибок с помощью THROW

Инструкция THROW предлагает более простой метод повышения ошибок в коде и рекомендуется использовать для новой разработки T-SQL. Ошибки должны иметь номер ошибки не менее 50000.

БРОСАТЬ

THROW Отличается от RAISERROR нескольких способов:

  • При THROW возникновении нового исключения уровень серьезности всегда равен 16. Если THROW используется для повторного создания существующего исключения (без THROW параметров внутри CATCH блока), уровень серьезности исходного исключения сохраняется, поэтому для повторного увеличения системных CATCH ошибок из блока предпочтительнее использовать без THROW параметров.
  • Возвращаемые THROW сообщения не связаны с записями в sys.messages.
  • THROW SET XACT_ABORTчесть. При SET XACT_ABORT ON активности исключение, вызываемое THROW автоматически откатом текущей транзакции. RAISERROR не учитывается SET XACT_ABORT— это одна из основных причин THROW , предпочитаемых для новой разработки.

Important

Оператор непосредственно перед тем как THROW должен завершиться точкой с запятой (;), в противном случае возникает ошибка синтаксиса. Это распространенный блок спотыкания при внедрении THROW в существующем коде, который не запятой.

; THROW 50001, 'An error occurred', 1;

Запись кодов ошибок с помощью @@Error

Большинство традиционных кодов обработки ошибок в SQL Server приложениях были созданы с помощью@@ERROR. Структурированная обработка исключений предоставляет более эффективную альтернативу использованию @@ERROR и рекомендуется использовать новый код T-SQL. Он будет рассмотрен в следующем занятии. На основе @@ERRORбольшого объема существующего кода обработки ошибок SQL Server важно понимать, как работать с ним.

Ошибка

@@ERROR — системная переменная, содержащая номер ошибки последней ошибки. Одна из важных проблем заключается в @@ERROR том, что значение, которое оно содержит, быстро сбрасывается по мере выполнения каждой дополнительной инструкции.

Например, рассмотрим следующий код:

RAISERROR(N'Message', 16, 1);
IF @@ERROR <> 0
PRINT 'Error=' + CAST(@@ERROR AS VARCHAR(8));
GO

Вы можете ожидать, что при выполнении кода он вернет номер ошибки в напечатанной строке. Однако при выполнении кода возвращается следующее:

Msg 50000, Level 16, State 1, Line 1
Message
Error=0

Возникла ошибка, но было выведено сообщение "Error=0". В первой строке выходных данных можно увидеть, что ошибка, как ожидалось, была фактически 50000 с сообщением, переданным RAISERRORв . Это связано с тем, что IF инструкция, следующая за RAISERROR инструкцией, была выполнена успешно и привела @@ERROR к сбросу значения. По этой причине при работе @@ERRORс ней важно записать номер ошибки в переменную сразу после ее возникновения, а затем продолжить обработку с переменной.

Просмотрите следующий код, демонстрирующий следующее:

DECLARE @ErrorValue int;
RAISERROR(N'Message', 16, 1);
SET @ErrorValue = @@ERROR;
IF @ErrorValue <> 0
PRINT 'Error=' + CAST(@ErrorValue AS VARCHAR(8));

При выполнении этого кода он возвращает следующие выходные данные:

Msg 50000, Level 16, State 1, Line 2
Message
Error=50000

Номер ошибки правильно сообщается сейчас.

Централизованная обработка ошибок

Одна из других важных проблем с использованием @@ERROR для обработки ошибок заключается в том, что трудно централизировать код T-SQL. Обработка ошибок, как правило, разбросана по всему коду. Можно было бы централизировать обработку ошибок с @@ERROR помощью меток и GOTO инструкций. Тем не менее, большинство разработчиков сегодня посчитали бы это плохой практикой программирования.

Создание оповещений об ошибках

Для определенных категорий ошибок администраторы могут создавать оповещения SQL Server, так как они хотят получать уведомления сразу после их возникновения. Это может даже применяться к определяемым пользователем сообщениям об ошибках. Например, при заполнении журнала транзакций может потребоваться создать оповещение. Оповещения обычно используются для привлечения внимания администраторов к ошибкам высокой степени серьезности (например, 19 и выше).

Создание оповещений

Оповещения можно создавать для определенных сообщений об ошибках. Служба оповещений работает путем регистрации в качестве службы обратного вызова в службе ведения журнала событий. Это означает, что оповещения работают только на зафиксированных ошибках.

Существует два способа, как сделать так, чтобы ошибка вызвала оповещение: используйте параметр WITH LOG при генерации ошибки или измените сообщение, чтобы оно было зарегистрировано, выполнив sp_altermessage. Параметр WITH LOG влияет только на текущую инструкцию. Использование sp_altermessage изменяет поведение обработки ошибок для всех будущих использований.