在触发器中使用 DBMS_PIPE.PACK_MESSAGE 和 DBMS_PIPE.SEND_MESSAGE

Posted

技术标签:

【中文标题】在触发器中使用 DBMS_PIPE.PACK_MESSAGE 和 DBMS_PIPE.SEND_MESSAGE【英文标题】:Using a DBMS_PIPE.PACK_MESSAGE and DBMS_PIPE.SEND_MESSAGE in a trigger 【发布时间】:2020-05-02 13:58:38 【问题描述】:

环境:Oracle 12c

我正在研究在将被许多用户使用的表触发器中使用 Oracle DBMS_PIPE。触发器将仅在 STATUS 更新时触发,如下所示:

CREATE OR REPLACE TRIGGER MY_TRG  
AFTER UPDATE OF STATUS ON "MY_TABLE"  
REFERENCING NEW AS NEW OLD AS OLD  
FOR EACH ROW  
declare  
   v_status    INTEGER;  
begin      
    if :OLD.status = 'ERROR' and (:NEW.status = 'OK' or :NEW.status = 'ERROR') then  
       DBMS_PIPE.PACK_MESSAGE(:OLD.id_key);  
       DBMS_PIPE.PACK_MESSAGE(:NEW.status);  

       v_status := DBMS_PIPE.SEND_MESSAGE('MY_PIPE');  

       if v_status != 0 THEN  
         raise_application_error(num => -20002,msg => 'error message on trigger!');  
      end if;  
    end if;
  end;  

以下调用将从 Oracle APEX 页面进程发起,多个用户可以在该进程中再次提交。

DBMS_PIPE.receive_message(pipename => 'MY_PIPE', timeout  => 10);   

我的问题是,对于这里的每个用户,我是否需要确保 PIPE NAME 是特定于每个用户的,以便他们只能在他们的 PIPE 中看到他们的消息,或者只有一个“MY_PIPE”管道名称可以处理所有事务多个用户?

如果每个用户都需要自己指定的 PIPE NAME,如果 SEND_MESSAGE('USER_1_PIPE') 是从表触发器触发的,我该怎么做,而我的 receive_message_proc 将不知道这个 'USER_1_PIPE' 名称。

我的创建管道是这样的:

v_res := DBMS_PIPE.create_pipe(pipename => 'MY_PIPE', private => TRUE);  

我假设我需要用他们自己的私有管道名称标记每个用户 - 这是正确的吗?

【问题讨论】:

这似乎取决于管道的类型。你能告诉我们CREATE PIPE声明吗? @wolφi 更新了我的帖子以反映您的问题。 【参考方案1】:

私有管道是创建它们的用户名的私有管道。如果您有多个人使用同一个用户帐户登录,那么他们都将能够看到该管道。

但也许更大的问题是管道不是事务性的。因此,触发触发的那一刻,消息就会被放入管道中……即使该事务稍后回滚、失败或其他任何最终不会更新状态的事情。此外,管道消息将在事务提交之前发送。在提交发生之前,另一个会话(接收该管道消息)将无法看到所做的更改,这可能导致时间不一致。

也许 AQ(高级队列)是您可能要考虑的替代方案。默认情况下,队列上的消息是事务性的,因此队列上的消息很好地绑定到您对 STATUS 的更改是否真的成功。

调用应用程序只是侦听队列而不是管道消息。

【讨论】:

嗨康纳 - 感谢您的回复。我实际上已经开始研究 AQ 并为此创建了一个新的 SO 线程 - 请参见此处:***.com/questions/61582908/…。如果您可以在此线程上进行测验,以寻找有关如何使用 AQ 方法的示例,将不胜感激。真的很感激。 明确决定使用 Oracle 高级队列方法而不是 DBMS_PIPES。

以上是关于在触发器中使用 DBMS_PIPE.PACK_MESSAGE 和 DBMS_PIPE.SEND_MESSAGE的主要内容,如果未能解决你的问题,请参考以下文章

如何在Oracle触发器中使用查询语句

MySQL:无法在触发器中使用信号

SQL 在触发器中使用临时表

在 BEFORE INSERT 触发器中使用 WHILE 循环

使用从查询中获取的变量在触发器语句中进行比较的问题

在 postgres 9.4 中使用触发器执行外部程序