Oracle: в какой ситуации использовать RAISE_APPLICATION_ERROR? - PullRequest
18 голосов
/ 19 ноября 2009

Мы можем использовать RAISE , чтобы вызвать исключение. Какие конкретные ситуации нам нужно использовать RAISE_APPLICATION_ERROR ?

Спасибо.

Ответы [ 4 ]

26 голосов
/ 19 ноября 2009

Существует два варианта использования 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 в блоке EXCEPTIONS. Установка для необязательного третьего аргумента значения TRUE означает, что RAISE_APPLICATION_ERROR включает исключение запуска в стеке, что может быть полезно для диагностики.

Более подробная информация содержится в Руководстве пользователя PL / SQL .

9 голосов
/ 19 ноября 2009

Вы используете 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 голосов
/ 19 ноября 2009

Просто для того, чтобы подробнее рассказать об ответе Генри, вы также можете использовать конкретные коды ошибок из метода_Rance_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;

Повышение_процедуры_подключения позволяет вам вызвать определенный код ошибки. В заголовке вашего пакета вы можете определить: gc_entity_not_found INTEGER := -20001;

Если вам нужны другие коды ошибок для других типов ошибок, вы можете определить другие коды ошибок, используя -20002, -20003 и т. Д.

Затем на стороне клиента вы можете сделать что-то вроде этого (этот пример для C #):

/// <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);
    }
}
1 голос
/ 19 ноября 2009

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

При использовании кода dotnet я просто использую «поднимать», механизм исключений dotnet автоматически фиксирует ошибку, переданную Oracle ODP и показанную в моем коде исключения catch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...