Если ваш триггер вызывает ошибку, оператор DELETE
завершается неудачно, и транзакция откатывается до неявной точки сохранения, созданной до запуска оператора. Это означает, что любые изменения, сделанные триггером, также будут отменены.
Вы можете обойти это, используя автономные транзакции. Что-то вроде
CREATE PROCEDURE write_audit
AS
PRAGMA AUTOMOMOUS_TRANSACTION;
BEGIN
INSERT INTO tpm_audit
VALUES( 'Query has attempted to delete root project version!',
sysdate );
commit;
END;
CREATE TRIGGER TPMDBO.PreventVersionDelete
BEFORE DELETE ON TPM_PROJECTVERSION
FOR EACH ROW
DECLARE
BEGIN
IF( :old.VERSIONID = 1 )
THEN
write_audit;
RAISE_APPLICATION_ERROR( -20001, 'Query has attempted to delete root project version!' );
END IF;
END;
Это поместит INSERT
в TPM_AUDIT
в отдельную транзакцию, которая может быть зафиксирована вне контекста оператора DELETE
. Будьте очень осторожны с использованием автономных транзакций, однако
- Если вы когда-нибудь обнаружите, что используете автономные транзакции для чего-то кроме записи в таблицу журнала, вы почти наверняка делаете что-то не так.
- Код в блоке PL / SQL, объявленном с использованием автономных транзакций, действительно автономен, поэтому он не может видеть незафиксированные изменения, внесенные текущим сеансом.
- Из-за согласованности записи вполне возможно, что Oracle частично выполнит оператор
DELETE
, несколько раз запустив триггер уровня строки, откатит эту работу и затем повторно выполнит DELETE
. Однако этот тихий откат не откатит изменения, сделанные автономной транзакцией. Поэтому вполне возможно, что один DELETE
из одной строки фактически вызовет срабатывание триггера более одного раза и, следовательно, создаст несколько строк в TPM_AUDIT
.