我想用 VERSIONID=1
阻止任何行在某个表中被删除。我还想将其记录在审计表中,以便我们可以查看何时发生这种情况以进行记录。我试图用触发器来做到这一点:
CREATE TRIGGER TPMDBO.PreventVersionDelete
BEFORE DELETE ON TPM_PROJECTVERSION
FOR EACH ROW
DECLARE
BEGIN
IF( :old.VERSIONID = 1 )
THEN
INSERT INTO TPM_AUDIT VALUES ('Query has attempted to delete root project version!', sysdate);
RAISE_APPLICATION_ERROR( -20001, 'Query has attempted to delete root project version!' );
END IF;
END;
我得到以下结果:
SQL> delete from TPM_PROJECTVERSION where PROJECTID=70 and VERSIONID=1;
delete from TPM_PROJECTVERSION where PROJECTID=70 and VERSIONID=1
*
ERROR at line 1:
ORA-20001: Query has attempted to delete root project version!
ORA-06512: at "TPMDBO.PREVENTVERSIONDELETE", line 6
ORA-04088: error during execution of trigger 'TPMDBO.PREVENTVERSIONDELETE'
然而,表
TPM_AUDIT
是空的。难道我做错了什么?
最佳答案
如果您的触发器引发错误,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
的上下文之外提交的单独事务中陈述。使用自治事务时要非常小心,但是DELETE
语句,多次触发行级触发器,回滚该工作,然后重新执行 DELETE
.但是,这种静默回滚不会回滚自治事务所做的更改。所以完全有可能是单个DELETE
单行实际上会导致触发器被触发多次,因此,在 TPM_AUDIT
中创建多行. 关于sql - 防止某些行在 Oracle 中被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8717799/