|
Программирование >> Oracle
ERROR at line 1: ORA-02290: check constraint (TKYTE.SYS C00157 0) violated ORA-06512: at TKYTE.P , line 5 ORA-06512: at line 2 tkyte@TKYTE816> select * from t; no rows selected tkyte@TKYTE816> select * from t2; Как видите, сервер Oracle счел вызов процедуры неделимым оператором. Клиент послал блок кода (BEGIN P; END;), и сервер Oracle окружил его операторами SAVEPOINT. Поскольку процедура Р не сработала, сервер Oracle восстановил базу данных в состояние, предшествовавшее ее вызову. Теперь, послав немного измененный блок, мы получим абсолютно другой результат: tkyte@TKYTE816> begin 2 Р; 3 exception 4 when others then null; 5 end; I fired and updated 1 rows I fired and updated 1 rows PL/SQL procedure successfully completed. tkyte@TKYTE816> select * from t; tkyte@TKYTE816> select * from t2; Мы выполнили блок кода, в котором игнорируются любые ошибки, и результат получился принципиально другим. Тогда как первый вызов процедуры Р не вызвал никаких изменений, в данном случае первый оператор INSERT выполняется успешно, и столбец cnt в таблице Т2 увеличивается на 1. Сервер Oracle считает оператором переданный клиентом блок. Этот оператор завершается успешно, самостоятельно перехватывая и игнорируя ошибку, так что фрагмент If error then rollback... не срабатывает, и сервер Oracle не выполняет откат до точки сохранения после его выполнения. Вот по- чему результаты работы процедуры частично Р сохраняются. Причина этого частичного сохранения прежде всего в том, что внутри Р соблюдается неделимость операторов: все операторы в процедуре Р неделимы. Процедура Р работает как клиент Oracle при пос]лке двух операторов INSERT. Каждый оператор INSERT либо успешно выполняется полностью, либо завершается неудачно. Это подтверждается тем фактом, что триггер таблицы Т срабатывает дважды и два раза изменяет таблицу Т2, хотя счетчик в Т2 отражает только одно изменение. Вокруг второго оператора INSERT, выполненного в процедуре Р, были установлены неявные точки сохранения. Различие между двумя приведенными блоками кода невелико, но его надо учитывать при разработке приложений. Добавление обработчика исключительных ситуаций в блок кода PL/SQL может радикально изменить его работу. Ниже приведен более корректный способ реализации того же подхода, расширяющий неделимость на уровне оператора до уровня всего блока PL/SQL: tkyte@TKrE816> begin 2 savepoint sp; 3 P; 4 exception 5 when others then 6 rollback to sp; 7 end; I fired and updated 1 rows I fired and updated 1 rows PL/SQL procedure successfully completed. tkyte@TKYTE816> tkyte@TKYTE816> select * from t; no rows selected tkyte@TKYTE816> select * from t2; CNT 0 Имитируя автоматически выполняемые сервером Oracle действия с помощью оператора SAVEPOINT, мы можем восстановить исходное поведение процедуры и при этом перехватывать и игнорировать ошибки. Требования целостности и транзакции Интересно разобраться, когда именно проверяются требования целостности. По умолчанию требования целостности проверяются после выполнения всего SQL-оператора. Обратите внимание: я написал SQL-оператора , а не просто оператора . Если в хранимой процедуре PL/SQL есть несколько операторов SQL, проверка требований целостности каждого оператора выполняется сразу же по завершении его выполнения, а не по завершении выполнения всей хранимой процедуры. Проверка требований целостности может быть программно отложена до завершения транзакции или до момента, когда разработчик сочтет необходимым их проверить. Итак, почему же требования проверяются после выполнения SQL-оператора, а не при выполнении? А потому, что одному оператору позволено кратковременно делать отдельные строки таблицы несогласованными. Попытка получить частичные результаты выполнения оператора приведет к отмене этих результатов сервером Oracle, даже если конечные результаты вполне допустимы. Пусть, например, имеется следующая таблица: tkyte@TKYTE816> create table t (x int unique); Table created. tkyte@TKYTE816> insert into t values (1); 1 row created. tkyte@TKYTE816> insert into t values (2) ; 1 row created. Теперь, пусть необходимо выполнить изменение нескольких строк: tkyte@TKYTE816> update t set x = x+1; 2 rows updated. Если бы сервер Oracle проверял требование после изменения каждой строки, то вероятность неудачного завершения изменений составляла бы 50%. Строки в таблице Т просматриваются в определенном порядке; поэтому, если бы сначала изменялась строка с Х=1, значение моментально дублировалось бы в столбце X, а изменение отвергалось. Поскольку сервер Oracle терпеливо ждет завершения оператора, он выполняется успешно, так как к моменту его завершения дублирующихся значений нет. Версии, начиная с Oracle 8.0, позволяют отложить проверку требований. Эта возможность может оказаться крайне полезной при выполнении различных операций. Например, в случае каскадного распространения изменения первичного ключа на внешние ключи. Многие скажут, что этого никогда не придется делать, что первичные ключи должны быть неизменны (и я тоже так скажу), но часто пользователи настаивают на возможности каскадного изменения. Отложенная проверка изменений позволяет это сделать. В предыдущих версиях в общем-то тоже можно было сделать каскадное изменение, но для этого приходилось выполнять огромный объем работы, да и сам подход имел определенные ограничения. С помощью отложенной проверки изменений задача становится практически тривиальной. Решение выглядит примерно так: tkyte@TKYTE816> create table p 2 (pk int primary key) 3 / Table created. tkyte@TKYTE816> tkyte@TKYTE816> create table с
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |