Стоит прочитать статью Oracle, на которую есть ссылка в другом ответе.
Несколько дополнительных вещей, которые нужно добавить - перехват исключения PL / SQL приводит к потере стека ошибок - то есть информации о том, какая именно строка вызвала исключение.
Это может затруднить отладку блоков кода, содержащих несколько мест, которые могут вызвать одно и то же исключение (т. Е. Если у вас несколько операторов SQL, которые могут возвращать NO_DATA_FOUND). Один из вариантов здесь - записать полный стек ошибок как часть вашего обработчика исключений.
EXCEPTION
WHEN TOO_MANY_ROWS THEN
myLogger('Some useful information',DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
Если вам нужно перехватывать исключения, сохраняйте обработку исключений как можно более локальной, до точки, которую вы хотите перехватить, и используйте только КОГДА ДРУГОЕ в крайнем случае.
Вы также можете «сделать что-то и повторно вызвать то же исключение»
EXCEPTION
WHEN TOO_MANY_ROWS THEN
closeSmtpConnection;
RAISE;
END;
Одной из наиболее полезных функций является возможность именовать и перехватывать внутренние исключения Oracle SQL.
DECLARE
recompile_failed EXCEPTION;
PRAGMA EXCEPTION_INIT (recompile_failed,-24344);
BEGIN
. . . . . .
EXCEPTION
WHEN recompile_failed THEN
emailErrors(pObjectType,pObjectName);
END;
Обратной стороной этого является возможность вызывать определенные пользователем исключения SQL
RAISE_APPLICATION_ERROR(-20001,'my text')
Это единственный способ распространения пользовательского текста в вызывающем приложении, так как пользовательские исключения pl / sql не пересекают границу области действия.
К сожалению, несмотря на то, что в документации сказано, что диапазон от -20000 до -20999 доступен для определенных пользователем исключений, некоторые из пакетов расширений Oracle используют эти серийные номера, поэтому вы не можете полагаться только на серийный номер для определения ошибки в языке вызова .
(Большинство людей, как правило, переносят RAISE_APPLICATION_ERROR в другой код, чтобы также регистрировать ошибку и часто выводить текст ошибки из таблицы)
Один трюк, который я нашел полезным, - это создать пакет с переменными состояния в теле пакета и простыми функциями установки и получения. В отличие от обновлений базы данных, информация в пакетах НЕ откатывается при ошибке.
В точке ошибки задайте информацию в вашем пакете, затем извлеките ее, используя методы получения на вашем языке вызова, для создания «нативного» исключения.
Что касается пользовательских исключений pl / sql - они могут быть полезны в локальном коде, но во многих случаях их можно избежать, используя другую структуру управления (т. Е. Избегайте их использования в качестве альтернативного GOTO).
Создание глобальных исключений в заголовках пакетов, чтобы указать возможные исключения, которые может возвращать пакет, кажется хорошей идеей, но конечный результат заключается в том, что ваш вызывающий код в конечном итоге вынужден обрабатывать каждое потенциальное исключение, которое может быть приведено в любом из основные пакеты.
Пройдя по этому самому маршруту в прошлом, я бы порекомендовал против него - сделать пакеты автономными и либо использовать RAISE_APPLICATION_ERROR, либо возвращать ошибки в виде текста.