|
Программирование >> Oracle
SAVEPOINT. Оператор SAVEPOINT позволяет создать в транзакции метку , или точку сохранения. В одной транзакции можно выполнять оператор SAVEPOINT несколько раз, устанавливая несколько точек сохранения. ROLLBACK TO <точка сохранения>. Этот оператор используется совместно с представленным выше оператором SAVEPOINT. Транзакцию можно откатить до указанной точки сохранения, не отменяя все сделанные до нее изменения. Таким образом, можно выполнить два оператора UPDATE, затем - оператор SAVEPOINT, а после него - два оператора DELETE. При возникновении ошибки или исключительной ситуации в ходе выполнения операторов DELETE транзакция будет откатываться до указанной оператором SAVEPOINT точки сохранения; при этом будут отменяться операторы DELETE, но не операторы UPDATE. SET TRANSACTION. Этот оператор позволяет устанавливать атрибуты транзакции, такие как уровень изолированности и то, будет ли она использоваться только для чтения данных или для чтения и записи. Этот оператор также позволяет привязать транзакцию к определенному сегменту отката. Вот и все операторы управления транзакциями. Чаще всего используются операторы COMMIT и ROLLBACK. Оператор SAVEPOINT имеет несколько специфическое назначение. Сервер Oracle часто использует его по ходу работы, но определенную пользу от него можно получить и в приложениях. Теперь можно приступить к изучению последствий неделимости оператора и транзакции. Рассмотрим следующий оператор: Insert into t values (1) ; Кажется вполне очевидным, что строка вставлена не будет, если из-за нарушения требования уникальности этот оператор не выполнится. Рассмотрим, однако, следующий пример, где при вставке или удалении строки в таблице Т срабатывает триггер, изменяющий значение столбца cnt в таблице Т2: tkyte@TKYTE816> create table t2 (cnt int) ; Table created. tkyte@TKYTE816> insert into t2 values (0); 1 row created. tkyte@TKYTE816> create table t (x int check (x>0)) ; Table created. tkyte@TKYTE816> create trigger t trigger 2 before insert or delete on t for each row 3 begin 4 if (inserting) then 5 update t2 set cnt = cnt +1; 6 else 7 update t2 set cnt = cnt -1; 8 end if; 9 dbms output.put line(I fired and updated sql%rowcount rows) ; Мы успешно вставили одну строку в таблицу Т, получив надлежащее сообщение: I fired and updated 1 rows. Следующий оператор INSERT нарушает ограничение целостности таблицы Т. Мне пришлось ввести exec NULL и выполнить тем самым пустой оператор, чтобы утилита SQL*Plus показала информацию, выданную с помощью пакета DBMS OUTPUT, (поскольку SQL*Plus не вгдает содержимое буфера DBMSOUTPUT после выполнения оператора SELECT), но и в этот раз было получено сообщение, что триггер сработал и изменил одну строку. Можно было бы предположить, что в таблице Т2 теперь будет значение 2, но мы видим там значение I. Сервер Oracle обеспечил неделимость переданного оператора вставки. Он достигает этого, неявно размещая операторы SAVEPOINT вокруг каждого из переданных операторов. Представленные выше операторы вставки на самом деле обрабатываются так: 10 end; 11 / Trigger created. В этой ситуации предполагаемые последствия менее очевидны. Если ошибка происходит после срабатывания триггера, должны ли остаться в силе изменения, сделанные триггером? То есть, если триггер сработал, изменив таблицу Т2, а строка не вставлена в таблицу Т, каким должен быть результат? Естественно, не хотелось бы, чтобы значение в столбце cnt таблицы Т2 было увеличено, если строка в таблицу Т не вставлена. К счастью, в Oracle переданный клиентом оператор (INSERT INTO T в данном случае) либо выполняется успешно полностью, либо не выполняется вообще. Это - неделимый оператор. В этом можно убедиться следующим образом: tkyte@TKYTE816> set serveroutput on tkyte@TKYTE816> insert into t values (1) ; I fired and updated 1 rows 1 row created. tkyte@TKYTE816> insert into t values (-1) ; insert into t values (-1) * ERROR at line 1: ORA-02290: check constraint (TKYTE.SYS C001570) violated tkyte@TKYTE816> exec null /* это необходимо для получения */ /* результатов dbms output */ I fired and updated 1 rows PL/SQL procedure successfully completed. tkyte@TKYTE816> select * from t2; CNT Savepoint statement1; Insert into t values (1) ; If error then rollback to statement1; Savepoint statement2; Insert into t values (-1) ; If error then rollback to statement2; Для программистов, привыкших работать с СУБД Sybase или SQL Server, это поначалу кажется странным. В этих СУБД все происходит в точности наоборот. В этих системах триггеры выполняются независимо от вызвавшего их срабатывание оператора. Если в них происходит ошибка, триггеры должны явно откатывать сделанные ими изменения, а затем возбуждать другую исключительную ситуацию для отката оператора, вызвавшего срабатывание. В противном случае выполненные триггером изменения могут остаться в силе, даже если вызвавший срабатывание оператор завершился неудачно. В Oracle неделимость операторов распространяется на любую необходимую глубину. В рассмотренном выше примере оператор INSERT INTO T вызвал срабатывание триггера, изменившего другую таблицу, а для этой таблицы есть триггер, удаляющий строки из еще одной таблицы, и так далее, но в любом случае либо все изменения выполняются успешно, либо ни одно. Для этого не надо применять специальные приемы кодирования - все работает именно так. Интересно отметить, что сервер Oracle считает оператором анонимный блок PL/SQL. Рассмотрим следующую хранимую процедуру: tkyte@TKrE816> create or replace procedure p 2 as 3 begin 4 insert into t values (1) ; 5 insert into t values (-1) ; 6 end; Procedure created. tkyte@TKYTE816> select * from t; no rows selected tkyte@TKYTE816> select * from t2; CNT Итак, имеется процедура, которая не должна сработать. Второй оператор вставки всегда будет завершаться неудачно. Давайте посмотрим, что произойдет, если выполнить эту хранимую процедуру: tkyte@TKYTE816> begin 2 Р; 3 end; I fired and updated 1 rows I fired and updated 1 rows begin
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |