可以为当前会话禁用 Oracle 触发器吗?

Posted

技术标签:

【中文标题】可以为当前会话禁用 Oracle 触发器吗?【英文标题】:Can an Oracle trigger be disabled for the current session? 【发布时间】:2013-03-17 13:17:47 【问题描述】:

我想在向表中插入数据之前禁用表上的特定触发器,但不会影响其他用户,这些用户可能正在更改同一个表中的数据。我找不到任何记录在案的方法来做到这一点。这是 Oracle 11g。

我能想到的最佳解决方案是创建一个会话变量,并让我的应用程序将其设置为触发器在工作之前检查的某个值。

强制性的反触发评论:我讨厌触发。

【问题讨论】:

:我不认为,您可以禁用特定会话的触发器,您可以做什么,更改触发器代码,并为其他会话执行。放置一个 if 条件`userenv('SESSIONID ') ` +1 讨厌触发器 @DavidAldridge - 抱歉你讨厌触发器。它们有自己的位置并且非常有用 - 但如果滥用,它们可能会导致维护噩梦。 (不要问我是怎么知道的 :-)。 如果您发现有必要针对某些特定条件禁用触发器,我建议您寻找重构相关代码的好机会。 @BobJarvis 作为应用程序业务逻辑的一部分,我认为触发器很糟糕。但是,对于应用程序外的日志记录和监控,它们非常棒。但当然,人们使用它们的目的是前者,我想主要是因为他们有一项大学作业,需要将它们用作业务逻辑的一部分,或者更糟糕的是强制执行约束。他们的任务不包括事后调试。 【参考方案1】:

将变量添加到现有包规范(或创建新包):

enable_trigger boolean := true;

将触发器中的代码括起来:

如果 enable_trigger then

结束如果;

当您想“禁用”触发器时,请将变量设置为 false。

最佳实践是将变量放在主体中并编写一个 set 过程和一个 get 函数。

【讨论】:

【参考方案2】:

我认为在 oracle 或其他 rdbms 中不可能为特定会话禁用触发器。

我的解决方案是,如果您知道登录的 CURRENT_USER 或 session_id,那么您可以在触发器中添加条件。

  IF SYS_CONTEXT ('USERENV', 'CURRENT_USER') <> '<XYZ>' THEN
    --do the operation

  END IF; 

你需要把这个条件放在你的触发器中

【讨论】:

没错。关于触发器的全部意义在于,只要事件发生,它们就会触发。 @Rene:感谢您提供可能的替代方案,但我不熟悉这种方法。需要阅读并对此进行一些动手操作。+1 所以用户 XYZ 永远不会执行代码。这是个好主意吗? @redcayuga:这取决于条件,程序员想要在什么情况下执行代码,我只是告诉他你不能为特定会话禁用触发器,为了达到他的要求,他需要用IF 条件更改触发器,但在我看来,你更好地回答了这个问题。【参考方案3】:

在过程中使用dbms_application_info.set_client_info(链接到oracle 文档)设置_client_info 并在触发器中读取它。

简单示例:

SET SERVEROUTPUT ON   
declare
CI_Status VARCHAR2(25 BYTE):='';
begin
--set the value
dbms_application_info.set_client_info('qwerty');
-- the value is sent an out to CI_Status when you want to read it
DBMS_APPLICATION_INFO.READ_CLIENT_INFO (CI_Status);
--Output the value in the console 
dbms_output.put_line('Value of CI_Status is: ' || CI_Status); 
end;

在您的程序中:

procedure spname is
    begin
      dbms_application_info.set_client_info('qwerty');
      --Do your update
      UPDATE tableName set a=b;
      --in case you still have the sesion opened, set it to null after
      dbms_application_info.set_client_info(null);
end;

在你触发:

create or replace TRIGGER Triggername
 BEFORE INSERT OR UPDATE
 ON tablename
 FOR EACH ROW
declare
CI_Status VARCHAR2(25 BYTE):='';
begin
--Retrieve the value into CI_Status the variable
DBMS_APPLICATION_INFO.READ_CLIENT_INFO(CI_Status); 
    IF INSERTING THEN
       null;
    ELSIF UPDATING THEN
          IF CI_Status = 'qwerty' then
             --Do nothing since you dont want the trigger to fire
              null;
          ELSIF CI_Status is null then
            :new.tablefield:= SYSDATE;
          END IF;
    END IF;
end Triggername;

完全禁用而不用担心并发

 procedure spname is
    begin    
      EXECUTE IMMEDIATE 'ALTER TRIGGER Triggername DISABLE';
      UPDATE tableName set a=b;
      EXECUTE IMMEDIATE 'ALTER TRIGGER Triggername ENABLE';
   end;

【讨论】:

【参考方案4】:

Oracle 版本可能对此有用吗?在另一个版本中创建不同的触发器并更改会话以使用该版本。

http://www.oracle-base.com/articles/11g/edition-based-redefinition-11gr2.php#editions

我必须承认我没有任何版本的实践经验。

【讨论】:

你可能会得到这个为你工作,但这不是版本的预期用途。

以上是关于可以为当前会话禁用 Oracle 触发器吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在导入过程中禁用Oracle约束条件和触发器

无法删除或截断 oracle 中的表

如何限制Oracle中没有一个禁用触发器

删除oracle 11g用户删除不掉,报ORA-04098错误!

oracle 中如何删除或修改 触发器?

Oracle启用和禁用触发器