sql - 防止某些行在 Oracle 中被删除

标签 sql oracle triggers oracle11g

我想用 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 的上下文之外提交的单独事务中陈述。使用自治事务时要非常小心,但是
  • 如果您发现自己将自治事务用于写入日志表以外的任何事情,那么您几乎肯定做错了。
  • 使用自治事务声明的 PL/SQL 块中的代码是真正自治的,因此它看不到当前 session 所做的未提交更改。
  • 因为写一致性,Oracle 完全有可能会部分执行一个 DELETE语句,多次触发行级触发器,回滚该工作,然后重新执行 DELETE .但是,这种静默回滚不会回滚自治事务所做的更改。所以完全有可能是单个DELETE单行实际上会导致触发器被触发多次,因此,在 TPM_AUDIT 中创建多行.
  • 关于sql - 防止某些行在 Oracle 中被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8717799/

    相关文章:

    java - Hibernate 映射 - 没有@Id 的连接表

    sql - 如何在 PL/SQL 中创建一个随时间段递增的循环

    mysql触发ckeck约束

    jenkins - jenkins 多分支管道中的分支索引会触发额外的构建,该构建已由 poll SCM 构建

    sql - 更高效的SQLite触发器来“汇总”多行

    mysql - 将此 MySQL 查询转换为 PyGreSQL

    SQL重复优化

    Oracle APEX 问题 - ORA 20987 : APEX - User nobody requires ADMIN privilege to perform this operation. - 请联系您的应用程序管理员

    sql - 尝试更改 Informix 数据库字符集

    sql - 使用查询结果更新现有表 SQL Server 2012