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

问题描述 投票:2回答:1

Env:Oracle 12c

我正在考虑在表触发器中使用Oracle DBMS_PIPE,该触发器将被许多用户使用。触发器将仅按以下状态更新时触发:

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);  

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

sql oracle plsql oracle12c
1个回答
0
投票

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.