Oracle CDC不能直接用JDBC Streaming实现,因官方JDBC驱动不支持真正流式监听,仅支持快照查询;必须依赖LogMiner、OGG或FDA等数据库层机制捕获变更。
Oracle CDC 为什么不能直接用 JDBC Streaming 查询实现
oracle 官方 jdbc 驱动不支持真正的流式拉取(即 resultset.type_forward_only + resultset.concur_read_only 并不能持续监听新数据),所谓 “streaming 查询” 在 oracle 场景下容易被误解为一边查一边 fetch,但本质仍是快照查询。真正捕获变更(insert/update/delete)必须依赖数据库层机制,不是应用层 jdbc 能绕过去的。
常见错误现象:ResultSet.next() 返回 false 后就终止,无法感知后续插入;或手动轮询 SELECT * FROM t WHERE ts > ? 导致漏行、重复、性能陡增。
- Oracle 没有类似 PostgreSQL 的
LISTEN/NOTIFY或 MySQL 的 binlog dump 协议暴露给 JDBC -
Statement.setFetchSize(Integer.MIN_VALUE)在 Oracle 中仅影响内存缓冲行为,不会触发“长连接推送” - 即使配合
ROWID或时间戳轮询,也无法可靠处理事务边界、回滚、批量提交等场景
真正可用的 Oracle CDC 方案只有三种
必须从 Oracle 数据库自身能力出发选型,而不是在 Java 里“模拟流”。主流且生产验证过的路径只有:
- Oracle GoldenGate (OGG):商业方案,支持抽取 redo log,低延迟、全 DML 捕获,Java 端通过 JMS/Kafka 接收变更事件
-
Oracle Database 12c+ 的 LogMiner + UTL_FILE 或 DBMS_LOGMNR:开源免费,但需 DBA 开启补充日志(
ADD SUPPLEMENTAL LOG DATA),Java 通过 JDBC 调用存储过程解析日志内容,实时性中等,有维护成本 - Oracle Flashback Data Archive (FDA):只支持 select 历史版本,不能捕获“正在发生的变更”,适合审计回溯,不适合流式消费
注意:DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER 是快照点切换,不是流;FLASHBACK_TRANSACTION_QUERY 视图只保留有限窗口,不可靠用于持续消费。
LogMiner + Java 的最小可行集成要点
如果决定走 LogMiner 路线,Java 层核心是定时执行解析逻辑,而非“建立流连接”。关键控制点在数据库侧配置和 Java 调用方式:
立即学习“Java免费学习笔记(深入)”;
- 必须提前执行:
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;(否则 UPDATE 缺少 old values) - LogMiner 会话需绑定具体归档日志范围,Java 中用
DBMS_LOGMNR.START_LOGMNR传入OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG - Java 查询日志结果应走
SELECT * FROM V$LOGMNR_CONTENTS WHERE OPERATION IN ('INSERT','UPDATE','DELETE'),注意过滤SQL_REDO和SQL_UNDO字段长度限制(可能被截断) - 每次解析后必须调用
DBMS_LOGMNR.END_LOGMNR,否则会话堆积导致 ORA-01308 错误
示例片段(JDBC 调用):
String sql = "SELECT SCN, TIMESTAMP, OPERATION, SQL_REDO FROM V$LOGMNR_CONTENTS " +
"WHERE SCN > ? AND OPERATION IN ('INSERT','UPDATE','DELETE') ORDER BY SCN"; 注意:SCN 不是严格递增序(因 RAC、并行事务),建议用 TIMESTAMP 辅助去重。
别碰“伪流式轮询”陷阱
很多团队试图用带时间戳字段(如 last_modified)的轮询模拟 CDC,这在 Oracle 下尤其危险:
- 应用未统一写该字段?触发器漏写?事务中先 insert 后 update 时间戳?都会导致漏数据
- Oracle 的
SYSTIMESTAMP在 RAC 环境存在节点间漂移,跨实例轮询时序错乱 - 高并发下
WHERE last_modified > ?无法避免幻读,且索引效率随数据增长急剧下降 - DDL 变更(如字段类型调整)会让旧轮询逻辑直接报错,而 LogMiner 至少能跳过异常 record
真正需要低延迟变更捕获时,LogMiner 或 OGG 是绕不开的。Java 的角色只是安全消费、反序列化、投递到下游——不是在 JDBC 层“造轮子”。


















