DBMS_AQ.REGISTER回调不触发主因是注册时namespace未设为DBMS_AQ.NAMESPACE_AQ或callback未用合法全名(如'SCOTT.AQ_CALLBACK_PROC'),且过程需有EXECUTE权限、签名严格匹配、非阻塞dequeue、显式提交。
DBMS_AQ.REGISTER 为什么注册后没触发回调
回调不触发,八成是注册时漏了 aq$_reg_info 的 namespace 设为 dbms_aq.namespace_aq,或者 callback 字段写的不是合法 pl/sql 过程全名(必须带 schema,比如 'scott.aq_callback_proc')。另外,用户得有 execute 权限在目标过程上,且该过程签名必须严格匹配:procedure p (context raw, reginfo sys.aq$_reg_info)。
-
callback值里不能带括号、参数,也不能是匿名块或函数 - 注册用的用户(执行
DBMS_AQ.REGISTER的 session)必须和队列所有者在同一实例,RAC 环境下不跨节点生效 - 队列需启用消息跟踪(
queue_table创建时设trace => TRUE),否则某些版本不会投递通知 - 检查
V$AQ_AGENT和DBA_QUEUE_SCHEDULES,确认注册已写入且状态为ENABLED
回调过程里如何安全读取消息而不阻塞
回调过程本质是 Oracle 后台异步调用,不能用 DBMS_AQ.DEQUEUE 默认的 WAIT 模式——它会卡住整个 AQ 通知线程,导致后续消息积压。必须显式设 wait_time => 0,并捕获 NO_DATA_FOUND 异常。
- 只 dequeue 当前 session 可见的、未过期、未被其他 consumer 获取的消息
- 务必在
DEQUEUE_OPTIONS中指定consumer_name,否则可能取到别人负责的消息 - 避免在回调里做耗时操作(如远程调用、大事务),超时默认 60 秒,超时后 Oracle 会终止该回调并标记失败
- 若需重试逻辑,别在回调里循环,应把失败消息 re-enqueue 到死信队列或延时队列
DECLARE
l_dequeue_options DBMS_AQ.DEQUEUE_OPTIONS_T;
l_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
l_message_handle RAW(16);
l_message SYS.AQ$_JMS_TEXT_MESSAGE;
BEGIN
l_dequeue_options.wait := 0; -- 关键:非阻塞
l_dequeue_options.consumer_name := 'MY_CONSUMER';
DBMS_AQ.DEQUEUE(
queue_name => 'MY_SCHEMA.MY_QUEUE',
dequeue_options => l_dequeue_options,
message_properties => l_message_properties,
payload => l_message,
msgid => l_message_handle
);
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL; -- 正常,队列空
END;ORA-24010: queue does not exist 错误怎么定位
这个错误表面是队列不存在,但真实原因常是:队列名大小写不一致、schema 名省略、或队列尚未 START。Oracle 对 queue_name 参数区分大小写,且要求格式为 schema.queue_name(即使当前用户就是 schema)。
- 查
DBA_QUEUES,确认queue_table和queue_name状态为VALID且status = 'ENABLED' - 用
DBMS_AQADM.START_QUEUE显式启动,哪怕建队列时设了queue_monitoring => TRUE - 如果队列在另一个 PDB,确保当前 session 已切换到对应容器(
ALTER SESSION SET CONTAINER = ...) - 动态 SQL 中拼接队列名时,别用双引号包裹——除非你真想强制大小写
回调触发后消息被重复处理怎么办
根本原因是回调过程执行成功但未提交,或执行中异常退出导致事务回滚,而 Oracle 认为“这次通知已送达”,下次又发一遍。这不是消息重复入队,而是同一消息被多次通知。
- 回调过程末尾必须显式
COMMIT,不能依赖自治事务或外部事务控制 - 不要在回调里做 DML 后直接抛异常;若要失败重试,先记录日志表(带
msgid和时间戳),再RAISE_APPLICATION_ERROR - 检查
DBA_QUEUE_TABLES的retention_time,太长会导致消息在队列表里停留久,增加重复风险 - 生产环境建议开启队列的
multiple_consumers => TRUE并配唯一consumer_name,避免多实例竞争
真正难缠的是回调过程里隐式提交(比如调用了含自治事务的过程)或数据库崩溃导致事务状态不一致——这种得靠幂等设计兜底,比如用 msgid 做去重主键。










