Oracle DDL в автономной транзакции - PullRequest
7 голосов
/ 01 марта 2010

Мне нужно выполнить несколько (до ~ 1000000) SQL-операторов в базе данных Oracle. Эти операторы должны приводить к окончательно согласованному состоянию в конце, и все операторы должны откатываться в случае возникновения ошибки. Эти заявления не приходят в ссылочном порядке. Поэтому, если включены ограничения внешнего ключа, одно из операторов может вызвать нарушение внешнего ключа, даже если это нарушение будет исправлено с помощью оператора, который будет выполнен позже.

Сначала я попытался отключить внешние ключи и включить их после выполнения всех операторов. Я думал, что смогу откатиться, когда произошло фактическое нарушение внешнего ключа. Хотя я ошибся, я обнаружил, что каждый оператор DDL в Oracle начинался с коммита, поэтому откатить операторы таким способом было невозможно. Вот мой скрипт для отключения внешних ключей:

begin 
  for i in (select constraint_name, table_name from user_constraints
            where constraint_type ='R' and status = 'ENABLED') 
    LOOP execute immediate 'alter table '||i.table_name||' disable constraint 
                           '||i.constraint_name||''; 
  end loop;
end;

После некоторых исследований я обнаружил, что рекомендуется выполнять операторы DDL, как в этом случае, в автономной транзакции. Поэтому я попытался выполнить операторы DDL в автономной транзакции. Это привело к следующей ошибке:

ORA-00054: ресурс занят и получен с указанным значением NOWAIT

Я предполагаю, что это потому, что основная транзакция все еще имеет блокировку DDL для таблиц.

Я что-то здесь не так делаю или есть другой способ заставить этот сценарий работать?

1 Ответ

8 голосов
/ 01 марта 2010

Есть несколько возможных подходов.

Первое, что нужно учитывать, это то, что вы делаете на уровне таблицы, будет применяться ко всем сеансам, использующим эту таблицу. Если у вас нет эксклюзивного доступа к этой таблице, вы, вероятно, не хотите удалять / воссоздавать ограничения или отключать / включать их.

Второе, что нужно учитывать, это то, что вы, вероятно, не хотите откатывать миллион вставок / обновлений. Откат может быть медленным.

Обычно я загружаю во временную таблицу. Затем выполните одну вставку из временной таблицы в таблицу назначения. В качестве единого утверждения Oracle применит все проверочные ограничения в конце.

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

SET CONSTRAINTS emp_job_nn, emp_salary_min DEFERRED;

Затем вы можете применить изменения, и при фиксации ограничения будут подтверждены.

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

...