Начиная с Oracle 8.0, мы также имеем возможность отложить проверку ограничений, что может оказаться довольно-таки выгодно для различных операций. Первое, что немедленно приходит в голову — это требование каскадного оператора UPDATE первичного ключа и его дочерних ключей. Многие люди возразят, что этого делать никогда не нужно, поскольку первичные ключи неизменны (я тоже принадлежу к их числу). Но многие другие настаивают на своем желании использовать каскадные UPDATE. Отложенные ограничения предоставляют такую возможность.
На заметку! Считается чрезвычайно плохой практикой выполнять каскадные обновления для модификации первичного ключа. Это нарушает само предназначение первичного ключа. Если вам нужно сделать это однажды, чтобы исправить некорректную информацию — это одно, но если вы постоянно поступаете так в своем приложении, то вам стоит вернуться и заново продумать дизайн, ибо вы выбрали неправильный атрибут в качестве ключа!
В предшествующих версиях можно было выполнять CASCADE UPDATE, но эта операция требует огромного объема работы и имеет определенные пределы. С отложенными ограничениями задача становится почти тривиальной. Код может выглядеть так, как показано ниже.
ops$tkyte@ORA10G> create table p
2 ( pk int primary key )
3 /
Table created.
Таблица создана.
ops$tkyte@ORA10G> create table c
2 ( fk constraint c_fk
3 references p(pk)
4 deferrable
5 initially immediate
6 )
7 /
Table created.
Таблица создана.
ops$tkyte@ORA10G> insert into p values ( 1 );
1 row created.
1 строка создана.
ops$tkyte@ORA10G> insert into c values ( 1 );
1 row created.
1 строка создана.
У нас есть родительская таблица P и дочерняя таблица C. Таблица C ссылается на таблицу P, и ограничение, используемое для обеспечения этого правила, называется C_FK (child foreign key — дочерний внешний ключ). Ограничение описано как DEFERRABLE, но установлено в INITIALLY IMMEDIATE. Это значит, что мы можем отложить проверку ограничения до COMMIT или до некоторого другого момента. Однако по умолчанию оно будет проверяться на уровне оператора. Это наиболее распространенный случай применения отложенных ограничений. Большинство существующих приложений не проверяют нарушение ограничений по оператору COMMIT, и лучше не менять этого. Согласно определению таблицы C, она ведет себя таким же образом, как всегда должны вести себя таблицы, но при этом предоставляет нам возможность изменить ее поведение. Попробуем воспользоваться некоторым DML для таблиц и посмотрим, что произойдет:
ops$tkyte@ORA10G> update p set pk = 2;
update p set pk = 2
*
ERROR at line 1:
ORA-02292: integrity constraint (OPS$TKYTE.C_FK) violated - child record found
ОШИБКА в строке 1:
ORA-02292: нарушение ограничения целостности (OPS$TKYTE.C_FK) — найдена
дочерняя запись
Поскольку ограничение находится в режиме IMMEDIATE, оператор UPDATE завершился неудачей. Изменим режим и попробуем снова:
ops$tkyte@ORA10G> set constraint c_fk deferred;
Constraint set.
Ограничение установлено.
ops$tkyte@ORA10G> update p set pk = 2;
1 row updated.
1 строка обновлена.
Теперь порядок. В демонстрационных целях я покажу, как явно проверить отложенное ограничение перед фиксацией, чтобы увидеть, согласуются ли модификации с бизнес-правилами (другими словами, проверить, не нарушаются ли ограничения). Будет хорошей идеей сделать это перед фиксацией или передачей управления какой-то другой части программы (которая может не ожидать отложенных ограничений):
ops$tkyte@ORA10G> set constraint c_fk immediate;
set constraint c_fk immediate
*
ERROR at line 1:
ORA-02291: integrity constraint (OPS$TKYTE.C_FK) violated - parent key not found
ОШИБКА в строке 1:
ORA-02291: нарушение ограничения целостности (OPS$TKYTE.C_FK) — найдена
родительская запись
Попытка завершается неудачей и немедленно возвращает ошибку, как и ожидалось, поскольку мы знали, что ограничение нарушается. Оператор UPDATE таблицы P не откатывается (поскольку это нарушило бы атомарность уровня оператора); он по-прежнему отложен. К тому же обратите внимание, что наша транзакция по-прежнему работает с отложенным ограничением C_FK, поскольку команда SET CONSTRAINT завершилась неудачей. Продолжим каскадным оператором UPDATE для таблицы C:
ops$tkyte@ORA10G> update c set fk = 2;
1 row updated.
1 строка обновлена.
ops$tkyte@ORA10G> set constraint c_fk immediate;Constraint set.
Ограничение установлено.
ops$tkyte@ORA10G> commit;
Commit complete.
Фиксация завершена.
Вот так это работает. Следует отметить, что для того, чтобы отложить ограничение, вы должны создать их именно таким образом — удалить и создать заново, чтобы изменить его с неотложенного на отложенное.
| < Предыдущая | Следующая > |
|---|


