oracle aq适用于主动触发的业务事件通知,需手动enqueue;真·变更捕获应选logminer或goldengate,jdbc轮询快照则易漏数、重复、性能差。
oracle aq 适合小规模、可控的业务事件通知
aq(advanced queuing)不是轮询机制,而是基于消息队列的异步通知方案。如果你真正想“轮询变更”,aq 并不匹配这个需求——它要求业务在数据变更时主动 enqueue 消息,比如在触发器或应用层调用 dbms_aq.enqueue。常见误用是以为开启 aq 就能自动捕获 dml 变更,其实不会。
适用场景:订单状态更新后主动发通知、审批流推进等明确的业务事件。不适用于“监听任意表字段变化”这类通用审计需求。
- 必须提前建队列、授权、启动队列(
DBMS_AQADM.START_QUEUE) - Java 端需使用 Oracle JDBC 的
AQSession和AQQueue,不能只靠普通Connection - 消息体通常为
RAW或自定义OBJECT类型,需在 Java 中注册对应STRUCT映射 - 超时拉取用
dequeue(options),但本质仍是“等待+拉取”,非数据库主动推送
CDC(Oracle GoldenGate 或 LogMiner)才是真·变更捕获
Oracle 官方 CDC 功能(DBMS_CDC_PUBLISH / DBMS_CDC_SUBSCRIBE)在 12c 后已弃用,现在实际可用的是两种替代路径:基于 LogMiner 的自研解析,或 GoldenGate(OGG)。Java 程序本身不直接读重做日志,必须通过中间层暴露变更流。
LogMiner 方案需要 DBA 开启补充日志(ADD SUPPLEMENTAL LOG DATA),并定期查询 V$LOGMNR_CONTENTS。Java 端只是定时执行 SQL 查询该视图——这才是你想要的“轮询”行为,但性能和归档压力极大,不建议生产高频使用。
- 每次
DBMS_LOGMNR.START_LOGMNR都有开销,应复用 session 并限制时间范围(STARTTIME/ENDTIME) -
V$LOGMNR_CONTENTS不是普通表,无法加索引,全扫描慢;务必用SQL_REDO+OPERATION+SEG_OWNER+TABLE_NAME过滤 - GoldenGate 则通过 trail 文件暴露变更,Java 可用 Kafka Connect(ogg-kafka-connect)或自研 Reader 读取 trail,延迟更低但部署复杂
别踩坑:JDBC ResultSet 轮询 SELECT 是最常见也最危险的伪轮询
很多团队用 SELECT * FROM t WHERE update_time > ? 加定时任务模拟“变更监听”,这根本不是 CDC,只是应用层轮询快照。问题极多:
- 漏变更:两次查询之间发生的
INSERT/UPDATE/DELETE若未被update_time覆盖(比如批量脚本绕过该字段),就丢失 - 重复消费:事务未提交时查到脏数据,或
update_time精度为秒导致同一秒内多次变更只取到一次 - 锁与性能:大表上
WHERE update_time > ?若无索引,每次扫全表;即使有索引,高并发轮询也会加剧 buffer busy waits - Oracle 的
ORA-01555快照过旧错误频发,尤其当轮询间隔长、UNDO_RETENTION 不足时
Java 实现建议:优先走 OGG + Kafka,次选 LogMiner + 增量游标
如果必须 Java 直连 Oracle 做轻量变更捕获,LogMiner 是唯一可行选项,但要规避全量扫描。关键是在 Java 中维护一个游标(如 SCN 或时间戳),每次只查增量段:
SELECT SCN, OPERATION, SQL_REDO FROM V$LOGMNR_CONTENTS WHERE SCN > ? AND SEG_OWNER = 'SCHEMA_NAME' AND TABLE_NAME = 'TBL' ORDER BY SCN
然后用 ResultSet.getBigDecimal("SCN") 更新下一次查询的起点。注意:SCN 不可跨实例保证严格顺序,且需定期调用 DBMS_LOGMNR.END_LOGMNR 释放资源。
GoldenGate 或 Debezium(配合 OGG)才是企业级方案,Java 应专注消费 Kafka topic,而非直连 Oracle 解析日志——那属于数据库运维范畴,不该由业务代码承担。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











