Обработка ошибок Oracle PL/SQL

Вопрос: Я создал триггер, который позволяет пользователю иметь 10 текущих размещенных заказов. Итак, теперь, когда клиент пытается разместить номер заказа 11, база данных оракула возвращает ошибку. Ну, 3 ошибки. ORA -20000: В настоящее время у вас 10 или более заказов. ORA-06512: в строке "C3283535.TRG_ORDER_LIMIT", строка 12 ORA-04088: ошибка во время запуска триггера C3283535.TRG_ORDER_LIMIT ' Верхняя

Вопрос:

Я создал триггер, который позволяет пользователю иметь 10 текущих размещенных заказов. Итак, теперь, когда клиент пытается разместить номер заказа 11, база данных оракула возвращает ошибку. Ну, 3 ошибки.

ORA -20000: В настоящее время у вас 10 или более заказов.

ORA-06512: в строке “C3283535.TRG_ORDER_LIMIT”, строка 12

ORA-04088: ошибка во время запуска триггера C3283535.TRG_ORDER_LIMIT ‘

Верхняя ошибка – это то, что я создал, используя:

raise_application_error (-20000: “В настоящее время у вас 10 или более заказов”.);

Я просто задался вопросом после поиска и пытался много способов изменить сообщения об ошибках для двух других ошибок или даже не показать их всем вместе с пользователем?

Вот код, который я использовал

create or replace trigger trg_order_limit before insert on placed_order for each row declare v_count number; begin — Get current order count select count(order_id) into v_count from placed_order where fk1_customer_id = :new.fk1_customer_id; — Raise exception if there are too many if v_count >= 10 then EXCEPTION WHEN OTHERS THEN raise_application_error(-20000, ‘You currently have 10 or more orders processing.’); end if; end;

Большое спасибо Ричард

Лучший ответ:

Происхождение исключения идет от внутреннего к внешнему блоку, в отличие от переменной области, которая идет от внешнего к внутреннему блоку. Для получения дополнительной информации об этом, прочитайте “Макрофлин” “Программирование с помощью PL/SQL”, глава 5.

То, что вы получаете здесь, представляет собой стек исключений – исключения, полученные от самых внутренних блоков до самых внешних блоков.

Когда вы вызываете исключение из триггера, оператор raise_application_error возвращает ошибку.

Затем он распространяется на триггерный блок, который говорит ORA-06512: at «C3283535.TRG_ORDER_LIMIT», line 12. Это связано с тем, что триггер рассматривает повышенное исключение как ошибку и останавливается для продолжения.

Затем ошибка распространяется на сеанс, который вызывает ORA-04088: error during execution of trigger ‘C3283535.TRG_ORDER_LIMIT’. Эта ошибка сообщает нам о том, где, как в какой части программы, была поднята ошибка.

Если вы используете внешнюю программу, такую как страницы сервера Java или PHP, вы сначала поймаете поднятую ошибку – 20000. Таким образом, вы можете отобразить то же самое для своего конечного пользователя.

РЕДАКТИРОВАТЬ :

О первой ошибке – ORA-20000, вы можете изменить ее в самой инструкции RAISE_APPLICATION_ERROR.

Если вы хотите обрабатывать ORA-06512, вы можете использовать ответ Uday Shankar, который поможет в ORA-06512 этой ошибки и отображает соответствующее сообщение об ошибке.

Но вы все равно получите последний ORA-04088. Если бы я был у вас на месте, я бы не стал беспокоиться, так как после получения ORA-20000 я бы поднял ошибку приложения на самой передней панели, скрывая все остальные данные от пользователя.

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

Ответ №1

В триггере вы можете добавить часть обработки исключений, как показано ниже:

EXCEPTION WHEN OTHERS THEN raise_application_error(-20000, ‘You currently have 10 or more orders processing.’); Ответ №2

Я вижу, что это довольно старый пост, но я думаю, что читатели должны знать, что

  1. Это фактически не обеспечивает соблюдение бизнес-правила (максимум 10 заказов). Если это просто “некоторый” номер, чтобы избежать слишком больших сумм, и вам все равно, если иногда у людей есть 12 заказов, тогда это может быть хорошо. Но если нет, подумайте о сценарии, когда у вас уже 9 заказов, а затем заказы для одного и того же клиента вставляются из двух разных сеансов/транзакций одновременно. В этом случае вы получите 11 заказов, не обнаружив эту ситуацию с переполнением. Таким образом, вы не можете полагаться на этот триггер на самом деле.
  2. Кроме того, вам может потребоваться перезапустить этот триггерный огонь при обновлении, если fk1_customer_id может быть обновлен (я видел реализации, где сначала NULL помещается в столбец FK, а затем обновляется до фактического значения). Вы можете подумать, реалистичен ли этот сценарий.
  3. В триггере есть основной недостаток. Вы находитесь внутри транзакции и внутри оператора, который в настоящее время выполняется, но еще не завершен. Итак, что, если вставка не является одной вставкой строки, а что-то вроде insert into placed_order (select… from waiting_orders…) что вы ожидаете от триггера?

Подобное бизнес-правило непросто обеспечить. Но если вы решите сделать это в триггере, вам лучше сделать это в триггер после инструкции (таким образом, не в триггере перед строкой). Триггер after after по-прежнему не будет видеть результаты других незафиксированных транзакций, но, по крайней мере, текущий оператор находится в определенном состоянии.

Фактически бизнес-правило МОЖЕТ принципиально применяться только в момент фиксации; но в базе данных Oracle нет такой вещи, как триггер ON-COMMIT. Вы можете сделать денормализацию количества записей в таблице клиентов (добавить столбец ORDER_COUNT) и поместить в эту таблицу отложенное ограничение (ORDER_COUNT <= 10). Но тогда вы все еще полагаетесь на правильное поддержание этого поля в своем коде.

Полностью надежная альтернатива, но несколько громоздкая, заключается в создании материализованного представления (что-то вроде SELECT fk_customer_id, count(*) order_count from placed_orders group by fk_customer_id, с FAST REFRESH ON COMMIT в таблице place_order и создания контрольного ограничения order_count <= 10 на материализованном виде. Это единственный способ надежно применять этот тип ограничений, не задумываясь о всех возможных ситуациях, таких как параллельные сеансы, обновления и т.д. Обратите внимание, что FAST REFRESH ON COMMIT замедлит вашу фиксацию, поэтому это решение не пригодно для больших объемов (вздох… Почему Oracle не предоставляет триггер ON COMMIT…)

Оцените статью
Добавить комментарий