Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 exception when others без raise - плохая практика?  [new]
shurka22
Member

Откуда:
Сообщений: 74
Коллеги, привет.
Давно пишу на PL/SQL, но так и не пришёл к выводу, хорошо ли ловить exception when others без raise.

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

0) преобразование поля из строки в дату или число - проблемы нет, каждое преобразование to_number или to_date обложено when others - и кричим, мол, неверный формат такого-то поля.
Проблема возникает при отлове застрела констрейнтов в операциях DML.

1) Первая версия обработки была написана "в лоб":
всё вставляем по таблицам. Если где застрелился констрейнт - ловим others в одном месте (в самом конце процедуры обработки одной записи), откатываем транзакцию (roolback to savepoint), в лог пишем стек ошибки (чтобы можно было понять, что именно сломалось), и метим запись как плохую. Переходим к следующей записи.
Беда-1 (самая большая беда) с таким подходом такая: если вдруг какой-то пакет (вызываемый в обработке) невалиден (ну мало ли, патч начали ставить, а джобы забыли погасить), то моментально все записи метятся как плохие.
Но на самом деле лучше бы остановить джоб и сказать: мол, ребята, у вас что-то с базой не то, почините, и начните сначала.
Беда-2 такая, что мы не знаем, что именно плохо во входящей записи. Но обычно это всё откатывается на тестах, и на бою проблемы крайне редки, и в случае сбоя нет критики подождать пару дней, пока разработчик выйдет на работу. На эту беду можно не обращать внимания.

2) подход 2: ловим others, и если SQLCODE один из:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body ... has been invalidated
ORA-06508: PL/SQL: could not find program unit being called: ...
делаем raise, чтобы остановить джоб.
По факту этот подход сейчас доминирует во всём написанном до меня коде.

3) Предыдущий подход хорош. Но есть подозрение, что этих ошибок недостаточно.
Например можно raise делать и для ошибки
ORA-04062 signature of package has been changed
или того хуже:
ORA-01033 ORACLE initialization or shutdown in progress
И создаётся ощущение, что этот путь не имеет конца. raise надо делать чуть ли не на любой ошибке.

4) Можно обложить каждую операцию вставки записи в каждую таблицу адовым количеством проверок: заменить этой логикой оракловые констрейнты: и чек-констрейнты, и форин-кеи, и уникальные ключи, итд.
Но это как-бы двойная работа: сначала мы в таблице пишем ограничения, а потом ещё и в коде их проверяем, чтобы не дай бог не застрелился табличный констрейнт.

5) Можно в конце блока обработки ловить строго те ошибки, которые создаются при операциях DML:
ORA-00001: unique constraint .. violated
ORA-02291: integrity constraint .. violated - parent key not found
ORA-01400: cannot insert NULL into ...
ORA-01407: cannot update .. to NULL
ORA-02290: check constraint .. violated
Но что-то опять создаётся ощущение (зря?), что этот набор ошибок сильно не полный.

Какой подход рекомендуют выбрать лучшие оракловоды?
Томкайт - он так вообще экстремист, и хотел бы запретить others (I truly wish we didn't even support WHEN OTHERS.)
Пишет, "ловите только то, что вы ожидаете получить":
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::p11_question_id:1155066278457

Я тут не привожу более сложный пример с deferred констрейнтами. Хотел бы получить ясность для более простого случая.
Ох, спасибо, что дочитали. Много вышло.
3 дек 18, 12:02    [21751880]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
казинак
Member

Откуда:
Сообщений: 1198
я всё не читал...
пользуюсь правилом:
when others
log record
raise

т.е. просто текст ошипки записать в лог,
RAISE, чтоб юзер видел что - косяк

ps
предусмотреть и обработать все ошибки невозможно
надо просто залоггировать,
а там уж видно будет как исправить...

это и есть концепция оракла,
все ошипки пишутся в алертлрог и в трейсы,

обработать все ошипки невозможно, но ты будешь видеть в логе что случилось
3 дек 18, 12:57    [21751947]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
andreymx
Member

Откуда: Запорожье
Сообщений: 49108
можно делать всё, когда понимаешь, как оно работает
3 дек 18, 13:02    [21751951]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
123йй
Member

Откуда:
Сообщений: 1445
shurka22
Давно пишу на PL/SQL..
Обработка - строки распарсить по полям, привести в нужный формат, вставить в кучу таблиц..

а доку почитать.
а все остальное лечится перезапуском джоба, если хотите с записью в лог/отправкой емайл.
3 дек 18, 13:04    [21751954]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
rpovarov
Member

Откуда:
Сообщений: 48
shurka22
(ну мало ли, патч начали ставить, а джобы забыли погасить)


Вот за это сразу канделябром по голове надо...

1) imho, любая ошибка, связанная не с логикой, а с базой - повод упасть, заплакать, позвать саппорт (программиста, DBA, человека с канделябром, etc.), потому что дальнейшие проблемы прогнозировать трудно, да и не надо

2) см. пункт 1

3) см. пункт 1, 2, и выбирайте потихоньку ухватистый канделябр для тех, что требует это обрабатывать в логике

4, 5) тут надо "или трусы надеть, или крестик снять"...
- или мы знаем, куда идут данные, какие там правила, и проверяем/фильтруем данные ещё до операции DML
- или нам лень и мы просто пишем в лог всю запись с диагностикой (откуда, куда, почему упали), чтобы потом кто-то на это посмотрел (кто? это его обязанность? не придёт ли он с канделябром?)
3 дек 18, 13:04    [21751955]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
andreymx
Member

Откуда: Запорожье
Сообщений: 49108
насколько я помню, на уровне БД ошибка ORA-04062 signature of package has been changed не ловится
или что-то поменялось?
3 дек 18, 13:06    [21751957]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
shurka22
Member

Откуда:
Сообщений: 74
rpovarov
4, 5) тут надо "или трусы надеть, или крестик снять"...
- или мы знаем, куда идут данные, какие там правила, и проверяем/фильтруем данные ещё до операции DML
- или нам лень и мы просто пишем в лог всю запись с диагностикой (откуда, куда, почему упали), чтобы потом кто-то на это посмотрел (кто? это его обязанность? не придёт ли он с канделябром?)

Коротко: нам лень.
Ну вот я тоже склоняюсь к этим двум вариантам. Максимально честный конечно же вариант 4. Но он и требует максимального кодирования, на которое постоянно нет времени. Поэтому и хотелось всё свалить на чек-констрейнты, и потом просто поймать их, залогировать, и потом по факту разобраться (разработка и бой живут близко). Собственно сейчас так и сделано. На этапе внедрения несколько раз ломались, смотрели лог, говорили, где поправить входной файл. А сейчас же уже пол-года - ничего не ломается. И вот ради чего делать двойную работу: и чек-констрейнты писать, и в коде проверять правильность заполнения. Куда проще понадеяться на констрейнт, поймать его, и сказать: мол не получилось, смотри в лог.
3 дек 18, 14:31    [21752086]     Ответить | Цитировать Сообщить модератору
 Re: exception when others без raise - плохая практика?  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16897
Самое сложное в exception handling - понять, что exception в общем случае error-ом не является.
Переведите дословно, помедитируйте.
И примедитируете к очень простой мысли: сама концепция структурированной обработки исключительных ситуаций предназначена для спрямления логики приложения.
Т.е. пишем основную мысль и отдельно описываем, что будем делать в каких-либо конкретных обстоятельствах, выводящих процесс из основного потока исполнения.
При этом "все прочие" исключения логикой заведомо не предусмотрены.
Посему обработчик when others по сути предназначен для самого верхнего уровня, который должен просто зафиксировать проблему и издать жалобное "мяу".
Другой вопрос, что сам модуль, столкнувшийся с непредвиденной ситуацией, может быть достаточно интеллектуально развит для самостоятельной фиксации (например, логирования) собственного состояния, однако это не отменяет обязанности информировать вышестоящих - потому raise обязателен.
3 дек 18, 15:26    [21752165]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить