В предыдущей заметке я писал о проблеме, с которой может столкнуться программист при использовании явных точек сохранения (savepoint). Сегодня я приведу конкретный пример, как избежать эту проблему.
Решение очень простое: pl/sql не запрещает создавать точки сохранения динамически. Вот пример:
declare spnt varchar2(32); begin spnt := 'savepoint_name'; execute immediate 'savepoint '||spnt; begin .. do something .. exception when others then execute immediate 'rollback to '||spnt; end; end;
Вместо execute immediate можно использовать такой вариант:
declare spnt varchar2(32); begin spnt := 'savepoint_name'; dbms_transaction.savepoint(spnt); begin .. do something .. exception when others then dbms_transaction.rollback_savepoint(spnt); end; end;
Замечу, что dbms_transaction внутри себя модифицирует имя точки сохранения, т.е. нельзя в одном блоке перемешивать оба варианта. Пример:
begin dbms_transaction.savepoint('savepoint_name'); .. rollback to savepoint_name; end;
вызовет ошибку: ORA-01086: savepoint 'SAVEPOINT_NAME' never established
Более того, dbms_transaction позволяет передавать числа, в качестве имени точки (видимо к имени добавляется некий префикс). Следующий пример будет корректен:
begin dbms_transaction.savepoint(1); .. dbms_transaction.rollback_savepoint(1); end;
Это позволяет использовать, например, последовательности (sequence) для динамического создания точек сохранения. Например так:
--create sequence savepoints_seq; declare spnt number; begin select savepoints_seq.nextval into spnt from dual; dbms_transaction.savepoint(spnt); .. dbms_transaction.rollback_savepoint(spnt); end; --drop sequence savepoints_seq;
Однако последовательности существуют вне транзакций, а точки сохранения действуют только в пределах транзакции. Поэтому имеет смысл написать свой пакет, в котором использовать простую целочисленную переменную, и наращивать её при обращении к ней.
1 коммент.:
Информация доступно изложена и была полезна. Спасибо.
Отправить комментарий