Oracle: какова ситуация с использованием RAISE_APPLICATION_ERROR?
Мы можем использовать RAISE для запуска исключения. В каких конкретных ситуациях нам нужно использовать RAISE_APPLICATION_ERROR?
Спасибо.
Ответы
Ответ 1
Для RAISE_APPLICATION_ERROR используется два использования. Во-первых, заменить общие сообщения об исключениях Oracle своими собственными, более значимыми сообщениями. Во-вторых, мы создаем собственные условия исключения, когда Oracle не бросит их.
Следующая процедура иллюстрирует оба способа использования. Он применяет бизнес-правило, в котором новые сотрудники не могут быть наняты в будущем. Он также отменяет два исключения Oracle. Один из них - DUP_VAL_ON_INDEX, который генерируется уникальным ключом на EMP(ENAME)
. Другое - это исключение, определяемое пользователем, если внешний ключ между EMP(MGR)
и EMP(EMPNO)
нарушен (поскольку менеджер должен быть уже существующим сотрудником).
create or replace procedure new_emp
( p_name in emp.ename%type
, p_sal in emp.sal%type
, p_job in emp.job%type
, p_dept in emp.deptno%type
, p_mgr in emp.mgr%type
, p_hired in emp.hiredate%type := sysdate )
is
invalid_manager exception;
PRAGMA EXCEPTION_INIT(invalid_manager, -2291);
dummy varchar2(1);
begin
-- check hiredate is valid
if trunc(p_hired) > trunc(sysdate)
then
raise_application_error
(-20000
, 'NEW_EMP::hiredate cannot be in the future');
end if;
insert into emp
( ename
, sal
, job
, deptno
, mgr
, hiredate )
values
( p_name
, p_sal
, p_job
, p_dept
, p_mgr
, trunc(p_hired) );
exception
when dup_val_on_index then
raise_application_error
(-20001
, 'NEW_EMP::employee called '||p_name||' already exists'
, true);
when invalid_manager then
raise_application_error
(-20002
, 'NEW_EMP::'||p_mgr ||' is not a valid manager');
end;
/
Как выглядит:
SQL> exec new_emp ('DUGGAN', 2500, 'SALES', 10, 7782, sysdate+1)
BEGIN new_emp ('DUGGAN', 2500, 'SALES', 10, 7782, sysdate+1); END;
*
ERROR at line 1:
ORA-20000: NEW_EMP::hiredate cannot be in the future
ORA-06512: at "APC.NEW_EMP", line 16
ORA-06512: at line 1
SQL>
SQL> exec new_emp ('DUGGAN', 2500, 'SALES', 10, 8888, sysdate)
BEGIN new_emp ('DUGGAN', 2500, 'SALES', 10, 8888, sysdate); END;
*
ERROR at line 1:
ORA-20002: NEW_EMP::8888 is not a valid manager
ORA-06512: at "APC.NEW_EMP", line 42
ORA-06512: at line 1
SQL>
SQL> exec new_emp ('DUGGAN', 2500, 'SALES', 10, 7782, sysdate)
PL/SQL procedure successfully completed.
SQL>
SQL> exec new_emp ('DUGGAN', 2500, 'SALES', 10, 7782, sysdate)
BEGIN new_emp ('DUGGAN', 2500, 'SALES', 10, 7782, sysdate); END;
*
ERROR at line 1:
ORA-20001: NEW_EMP::employee called DUGGAN already exists
ORA-06512: at "APC.NEW_EMP", line 37
ORA-00001: unique constraint (APC.EMP_UK) violated
ORA-06512: at line 1
Обратите внимание на другой вывод двух вызовов на RAISE_APPLICATION_ERROR в блоке ИСКЛЮЧЕНИЯ. Установка необязательного третьего аргумента в значение TRUE означает, что RAISE_APPLICATION_ERROR включает в себя триггерное исключение в стеке, которое может быть полезно для диагностики.
В в руководстве пользователя PL/SQL есть более полезная информация.
Ответ 2
Вы используете RAISE_APPLICATION_ERROR
, чтобы создать исключение/ошибку стиля Oracle, специфичное для вашего кода/потребностей. Хорошее использование этих средств позволяет создавать более четкие, более удобные в обслуживании и более легкие отладки.
Например, если у меня есть приложение, вызывающее хранимую процедуру, которая добавляет пользователя, и этот пользователь уже существует, вы обычно получите ошибку, например:
ORA-00001: unique constraint (USERS.PK_USER_KEY) violated
Очевидно, что эта ошибка и связанное сообщение не уникальны для задачи, которую вы пытались сделать. Создание собственных ошибок приложения Oracle позволяет вам более четко определить цель действия и причину проблемы.
raise_application_error(-20101, 'User ' || in_user || ' already exists!');
Теперь ваш код приложения может написать обработчик исключений, чтобы обработать это конкретное условие ошибки. Подумайте об этом как о способе заставить Oracle сообщать об ошибках, которые ваше приложение ожидает в "языке" (из-за отсутствия лучшего термина), которое вы определили и более значимом для вашего проблемного домена приложения.
Обратите внимание, что пользовательские ошибки должны быть в диапазоне от -20000 до -20999.
Следующая ссылка содержит много полезной информации по этой теме и исключений Oracle вообще.
Ответ 3
Чтобы подробнее рассказать об ответах Генри, вы также можете использовать определенные коды ошибок, начиная с raise_application_error и обрабатывать их соответственно на стороне клиента. Например:
Предположим, что у вас была процедура PL/SQL, подобная этой, чтобы проверить наличие записи местоположения:
PROCEDURE chk_location_exists
(
p_location_id IN location.gie_location_id%TYPE
)
AS
l_cnt INTEGER := 0;
BEGIN
SELECT COUNT(*)
INTO l_cnt
FROM location
WHERE gie_location_id = p_location_id;
IF l_cnt = 0
THEN
raise_application_error(
gc_entity_not_found,
'The associated location record could not be found.');
END IF;
END;
Функция raise_application_error позволяет вам поднять конкретный код ошибки. В заголовке пакета вы можете определить: gc_entity_not_found INTEGER := -20001;
Если вам нужны другие коды ошибок для других типов ошибок, вы можете определить другие коды ошибок, используя -20002, -20003 и т.д.
Затем на стороне клиента вы можете сделать что-то вроде этого (этот пример для С#):
/// <summary>
/// <para>Represents Oracle error number when entity is not found in database.</para>
/// </summary>
private const int OraEntityNotFoundInDB = 20001;
И вы можете выполнить свой код в try/catch
try
{
// call the chk_location_exists SP
}
catch (Exception e)
{
if ((e is OracleException) && (((OracleException)e).Number == OraEntityNotFoundInDB))
{
// create an EntityNotFoundException with message indicating that entity was not found in
// database; use the message of the OracleException, which will indicate the table corresponding
// to the entity which wasn't found and also the exact line in the PL/SQL code where the application
// error was raised
return new EntityNotFoundException(
"A required entity was not found in the database: " + e.Message);
}
}
Ответ 4
если ваше приложение принимает ошибки, исходящие из Oracle, тогда вы можете его использовать. у нас есть приложение, каждый раз, когда возникает ошибка, мы вызываем raise_application_error, приложение будет всплывать красным полем, чтобы показать сообщение об ошибке, которое мы предоставляем с помощью этого метода.
При использовании dotnet-кода я просто использую "повышение", исключение dotnet. Механизм автоматически фиксирует ошибку, переданную Oracle ODP, и отображается внутри моего кода исключения catch.