在触发器中使用 DBMS_PIPE.PACK_MESSAGE 和 DBMS_PIPE.SEND_MESSAGE
Using a DBMS_PIPE.PACK_MESSAGE and DBMS_PIPE.SEND_MESSAGE in a trigger
环境:Oracle 12c
我正在考虑在许多用户将使用的 table 触发器中使用 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')
是从 table 触发器触发的,我的 receive_message_proc将不知道这个 'USER_1_PIPE' 名称。
我的创建管道是这样的:
v_res := DBMS_PIPE.create_pipe(pipename => 'MY_PIPE', private => TRUE);
我想我需要用他们自己的私人管道名称来标记每个用户 - 这是否正确?
私有管道对于创建它们的 用户名 是私有的。如果您有多个人使用同一个用户帐户登录,那么他们都将能够看到该管道。
但也许更大的问题是管道不是事务性的。因此,触发触发的那一刻,消息就会被放入管道中……即使该事务后来回滚、失败或其他任何最终没有更新状态的事情。此外,管道消息将在事务提交之前发送。在提交发生之前,另一个会话(接收该管道消息)将无法看到所做的更改,这可能导致时间不一致。
也许 AQ(高级排队)是您可能想要考虑的替代方案。默认情况下,队列上的消息是事务性的,因此队列上的消息可以很好地绑定到您对 STATUS 的更改是否真的成功。
调用应用程序只监听队列而不是管道消息。
环境:Oracle 12c
我正在考虑在许多用户将使用的 table 触发器中使用 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')
是从 table 触发器触发的,我的 receive_message_proc将不知道这个 'USER_1_PIPE' 名称。
我的创建管道是这样的:
v_res := DBMS_PIPE.create_pipe(pipename => 'MY_PIPE', private => TRUE);
我想我需要用他们自己的私人管道名称来标记每个用户 - 这是否正确?
私有管道对于创建它们的 用户名 是私有的。如果您有多个人使用同一个用户帐户登录,那么他们都将能够看到该管道。
但也许更大的问题是管道不是事务性的。因此,触发触发的那一刻,消息就会被放入管道中……即使该事务后来回滚、失败或其他任何最终没有更新状态的事情。此外,管道消息将在事务提交之前发送。在提交发生之前,另一个会话(接收该管道消息)将无法看到所做的更改,这可能导致时间不一致。
也许 AQ(高级排队)是您可能想要考虑的替代方案。默认情况下,队列上的消息是事务性的,因此队列上的消息可以很好地绑定到您对 STATUS 的更改是否真的成功。
调用应用程序只监听队列而不是管道消息。