ПрограммированиеDatabase Developer

Как реализовать эффективные процедуры обработки ошибок и отладки в хранимых процедурах (stored procedures) SQL? Какие механизмы предусмотрены для отлова и логирования ошибок? Отличаются ли эти подходы в разных СУБД?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В хранимых процедурах можно и нужно обрабатывать ошибки с помощью специальных конструкций.

В SQL Server главные механизмы — блоки TRY...CATCH, где все ошибки внутри TRY отлавливаются, и в CATCH можно зафиксировать детали. Там доступны функции вроде ERROR_NUMBER(), ERROR_MESSAGE() для получения деталей.

BEGIN TRY -- Рискованная операция UPDATE Accounts SET balance = balance - 100 WHERE id = 1; END TRY BEGIN CATCH INSERT INTO ErrorLog( ErrorTime, ErrorNumber, ErrorMessage, UserName ) VALUES ( GETDATE(), ERROR_NUMBER(), ERROR_MESSAGE(), SUSER_SNAME() ); -- Дополнительное восстановление или ROLLBACK END CATCH

В Oracle чаще используются EXCEPTION-блоки:

BEGIN UPDATE ...; EXCEPTION WHEN OTHERS THEN INSERT INTO error_log VALUES (..., SQLERRM); END;

Моменты, о которых важно помнить:

  • Не все ошибки обрабатывает CATCH, например, ошибки парсинга или компиляции сбросят транзакцию до входа в TRY.
  • Для логирования информации важно иметь отдельную таблицу для ошибок.
  • Логировать стоит как можно больше: текст ошибки, номер, имя пользователя, параметры операции.
  • В разных СУБД синтаксис и возможности отличаются.

Вопрос с подвохом.

Может ли исключение в блоке CATCH привести к потере контекста ошибки? Каким образом реализовать вложенную обработку ошибок?

Ответ и пример: Если в CATCH-блоке произойдет ошибка (например, из-за недоступности таблицы ErrorLog), то оригинальный контекст ошибки теряется, и информация о причине сбоя может быть утеряна.

Чтобы предохраниться, инкапсулируйте логирование в отдельную процедуру с собственным TRY...CATCH, чтобы всегда ловить "ошибку в обработчике ошибок".

BEGIN TRY -- main code END TRY BEGIN CATCH EXEC LogError @Error = ERROR_MESSAGE(); END CATCH -- Процедура LogError сама содержит свой TRY...CATCH

История

Проект: Финансовая отчетность. В хранимых процедурах добавили блоки TRY...CATCH, но не залогировали параметры, с которыми происходила ошибка. В результате при отлове критических сбоев приходилось вручную искать ситуацию из бэкапа — root cause был неочевиден.


История

Проект: Автоматизация документооборота (Oracle). В EXCEPTION-блоке забыли логировать имя пользователя. Через неделю расследования обнаружили, что кто-то умышленно "ломал" документы — выяснили только по косвенным признакам в журнале аудита.


История

Проект: E-commerce. Процедура при сбое писала ошибку в ErrorLog. Однажды таблица Log была заблокирована разросшейся транзакцией, и попытка логирования привела к вложенной ошибке, которая перезаписала оригинальную причину и очистила стек ошибок. Исправили внедрением дополнительной таблицы для критических сбоев и многоуровневого логирования.