DBMS_CHANGE_NOTIFICATION 和 NEW_REG_START
Posted
技术标签:
【中文标题】DBMS_CHANGE_NOTIFICATION 和 NEW_REG_START【英文标题】:DBMS_CHANGE_NOTIFICATION and NEW_REG_START 【发布时间】:2011-08-21 07:33:31 【问题描述】:我阅读了一些关于如何将 DBMS_CHANGE_NOTIFICATION 用于异步触发器的示例。
仅当 STATUS = 1709003 时,我才需要为表 CONTENT 创建触发器。
所以我创建了以下程序:
CREATE OR REPLACE PROCEDURE tables_changed_chnt(ntfnds IN SYS.chnf$_desc) IS
l_table_name VARCHAR2(60);
l_event_type NUMBER;
l_numtables NUMBER;
status NUNBER;
Row_id VARCHAR2(20);
numrows NUMBER;
token varchar2(100);
subject varchar2(100);
message varchar2(100);
result varchar2(100);
planid number := 0;
userId number := -10000;
stoponefromatmissing number := 0;
timetostopprocess number := 0;
retrials number := 2;
stoponeinvalidaddress number := 0;
NL_CONTENT number:=-1;
event_status number:=-1;
BEGIN
l_numtables := ntfnds.numtables;
l_event_type := ntfnds.event_type;
IF l_event_type = DBMS_CHANGE_NOTIFICATION.EVENT_OBJCHANGE THEN
FOR i IN 1 .. l_numtables LOOP
l_table_name := ntfnds.table_desc_array(i).table_name;
if l_table_name = 'CONTENT' then
IF (bitand(operation_type, DBMS_CHANGE_NOTIFICATION.ALL_ROWS) = 0) THEN
numrows := ntfnds.table_desc_array(i).numrows;
ELSE
numrows :=0; /* ROWID INFO NOT AVAILABLE */
END IF;
FOR j IN 1..numrows LOOP
Row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
select NL_CONTENT_ID into NL_CONTENT from CONTENT where rownum=:Row_id;
select event_status_code into status from CONTENT where rownum=:Row_id;
if (status = 1709003) then
select NL_CONTENT_PLAN_ID into planid from NL_CONTENT where NL_CONTENT_ID=:NL_CONTENT;
result := workflow_cust.om_start_delivery(token,
subject,
message,
planid,
userId,
stoponefromatmissing,
timetostopprocess,
retrials,
stoponeinvalidaddress);
end if;
END LOOP;
end if
END LOOP;
END IF;
END;
我看到我需要用类似的东西来调用它:
DECLARE
REGDS SYS.CHNF$_REG_INFO;
regid NUMBER;
cust_id varchar2(20);
qosflags NUMBER;
BEGIN
qosflags := DBMS_CHANGE_NOTIFICATION.QOS_RELIABLE + DBMS_CHANGE_NOTIFICATION.
QOS_ROWIDS;
REGDS := SYS.CHNF$_REG_INFO ('SP_EVENT_GENERATE', qosflags, 0,0,0);
regid := DBMS_CHANGE_NOTIFICATION.NEW_REG_START (REGDS);
/* registe the customer table */
SELECT CUSTID INTO cust_id FROM TB_CUSTOMER WHERE ROWNUM=1;
DBMS_CHANGE_NOTIFICATION.REG_END;
END;
我需要写什么而不是SELECT CUSTID INTO cust_id FROM TB_CUSTOMER WHERE ROWNUM=1;
有没有办法检索已更改的对象,而不是仅检索 rowid - 因为这样可以节省我在第一个过程中进行查找的时间?
【问题讨论】:
为什么触发器需要是aysnc?当状态更新时,将消息排入队列或将行写入另一个表的正常触发器不能更简单地解决您的问题吗? 因为我的触发器调用了 Web 服务。我没有写完整的代码。调用它可能需要 20 秒,这可能会卡住我的应用程序 【参考方案1】:在注册块中(DBMS_CHANGE_NOTIFICATION.NEW_REG_START
和 DBMS_CHANGE_NOTIFICATION.REG_END
之间),您需要对表 CONTENT 执行一个简单的查询,以注册您对该表的更改的兴趣,例如:
SELECT select NL_CONTENT_ID into NL_CONTENT from CONTENT WHERE ROWNUM = 1;
通过 ROWID 访问非常快。因此,除了您可以将两个查询合并为一个之外,我认为没有任何节省时间的潜力:
select NL_CONTENT_ID, EVENT_STATUS_CODE into NL_CONTENT, STATUS from CONTENT
where ROWID = Row_id;
请注意,我更改了 WHERE 子句:它是 ROWID 而不是 ROWNUM。
顺便说一句:行:
REGDS := SYS.CHNF$_REG_INFO ('SP_EVENT_GENERATE', qosflags, 0,0,0);
应该是:
REGDS := SYS.CHNF$_REG_INFO ('TABLES_CHANGED_CHNT', qosflags, 0,0,0);
或者你的存储过程应该重命名为SP_EVENT_GENERATE
。
【讨论】:
以上是关于DBMS_CHANGE_NOTIFICATION 和 NEW_REG_START的主要内容,如果未能解决你的问题,请参考以下文章