必须手动配置xa连接、ldap/jndi注册和显式启动队列,否则onmessage()不触发;因oracle aq监听依赖队列启动、权限授权、字符集al32utf8及xa事务一致性,直连或非xa模式将导致消息丢失或静默失败。

不能用标准 JMS 自动配置,必须手动构造 XA 连接 + LDAP/JNDI 注册 + 显式启动队列,否则 onMessage() 永远不触发。
为什么 MessageConsumer.setMessageListener() 设了却没回调?
这不是 Java 代码写错了,而是 Oracle AQ 的监听生命周期和权限模型没对齐。
- Queue 消费必须确保队列已启动:
DBMS_AQADM.START_QUEUE('QUEUE_TEST'),否则receive()或 listener 都会无限阻塞 - Topic 消费必须先调用
connection.setClientID("myclient"),否则createDurableSubscriber()静默失败,日志里连异常都没有 - 用户缺少
DEQUEUE_ANY权限,或未被显式授权具体队列:DBMS_AQADM.GRANT_QUEUE_PRIVILEGE('dequeue', 'QUEUE_TEST', 'aquser') - 连接用的是连接池(如 HikariCP),而 DCN/AQ 监听绑定的是物理连接句柄——连接被池回收后,监听即失效,且不报错
怎么配 JNDI 才能让 AQjmsXAConnectionFactory 查到?
Oracle AQ 的 JNDI 不是 Spring Boot 里那种内存 Map 式的 fake JNDI,它必须指向真实注册源:LDAP、OID 或本地 Wallet 文件。
- 禁用所有“直连幻想”:
java.naming.provider.url不能是jdbc:oracle:thin:@...,否则抛javax.naming.NameNotFoundException - 开发阶段可临时用嵌入式工厂:
oracle.jms.AQjmsInitialContextFactory,但仅限单机测试,生产环境必须走 LDAP - 生产配置示例:
java.naming.provider.url=ldap://oid-host:389,且java.naming.security.principal必须是 OID 中注册的服务账号 - 如果用 Oracle Wallet,
java.naming.provider.url应为file:/path/to/wallet,并确保ojdbc8.jar和aqapi.jar均在 classpath
为什么必须用 AQjmsXAConnectionFactory 而不是普通 ConnectionFactory?
因为你要的不是“消息收了就完事”,而是“消息出队 + 数据库更新”原子提交。非 XA 模式下这两者根本不在一个事务分支里。
- 用
AQjmsConnectionFactory:出队走独立事务,session.commit()只提交出队动作;SQL 更新若回滚,消息就丢了 - 用
AQjmsXAConnectionFactory:需从XAConnection获取XASession,再创建MessageConsumer,才能参与两阶段提交 - Spring Boot 中必须禁用
JmsAutoConfiguration,手写@Bean注册XAConnectionFactoryBean,并关联JtaTransactionManager - 数据库字符集必须是
AL32UTF8,否则中文 payload 解析为乱码,且无任何异常提示
最易被忽略的一点:队列表(queue_table)和队列(queue)必须由 DBA 或具备 aq_administrator_role 的用户创建,普通应用用户只应有 DEQUEUE_ANY 和具体队列的细粒度授权。试图让应用用户自己建队列表,大概率触发 ORA-24010: queue table does not exist 或静默失败。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











