oracle cdc 与 continuous query 不同,官方无原生continuous query功能;可靠cdc方案仅logminer、goldengate和dbms_flashback+flashback_transaction_query三种,其中logminer是唯一免商业许可且能解析归档日志dml变更的方案。
oracle cdc 与 continuous query 不是一回事
oracle 官方没有叫 continuous query 的原生功能,这不是 sql server 的 change tracking 或 postgresql 的 listen/notify。你真正需要的是变更数据捕获(cdc)能力,而 oracle 提供的可靠路径只有三种:logminer、oracle goldengate(ogg)、或 oracle database 12c+ 的 dbms_flashback + flashback_transaction_query 配合轮询。其中 logminer 是唯一无需额外商业许可、能从归档日志中解析 dml 变更的方案。
用 LogMiner 实现最小可行监控流程
LogMiner 不是“开箱即用”的监听器,它本质是日志解析工具,必须手动启动、添加日志、查询、清理。C# 中调用需通过 Oracle Data Provider for .NET(ODP.NET)执行 PL/SQL 调用,不能靠纯 SQL 查询实现“实时流”。常见错误是试图用 SELECT * FROM V$LOGMNR_CONTENTS 直接查出未提交事务——这会报 ORA-01306: not in a logminer session。
- 先确保数据库开启补充日志:
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA; - 在 C# 中用
OracleCommand执行DBMS_LOGMNR.START_LOGMNR,关键参数包括OPTIONS(如DBMS_LOGMNR.COMMITTED_DATA_ONLY)、STARTSCN/ENDSCN(避免全库扫描) - 每次查询
V$LOGMNR_CONTENTS后必须调用DBMS_LOGMNR.END_LOGMNR,否则下次START_LOGMNR会失败 - 不要依赖
SQL_REDO字段直接执行——它可能含绑定变量、DDL、或跨事务语句;应提取OPERATION(INSERT/UPDATE/DELETE)、SEG_OWNER、TABLE_NAME、ROW_ID和SESSION_INFO做轻量判断
为什么不用 ODP.NET 的 ChangeNotification(AQ-based)
Oracle 提供的 OracleDependency 类看似支持“查询变更通知”,但它底层依赖 Advanced Queuing(AQ),只对 SELECT 结果集变化有效,且要求查询满足严格限制:必须是单表、无函数、无 JOIN、有主键,并且数据库端需启用 ENABLE TABLE FOR CHANGE NOTIFICATION。实际中,它无法捕获 INSERT/UPDATE/DELETE 的原始行变更,仅在结果集整体失效时触发一次通知,延迟高、不可靠,ORA-04043 或 ORA-24915 错误频发。
- 启用后若表结构变更(如加列),依赖自动失效,C# 端无明确异常提示
- 通知不带变更详情,只返回“某查询结果可能已变”,仍需重新查全量
- 高并发下 AQ 队列积压会导致通知丢失,且无法保证顺序
真正可用的 C# 架构建议
放弃“实时流”幻想,接受准实时(秒级延迟)+ 增量拉取模式。LogMiner 每次会话处理 SCN 范围有限(尤其归档日志多时),应设计为:后台线程定期获取当前 SCN → 计算上次处理到的 SCN 区间 → 启动 LogMiner 解析 → 提取变更 → 更新本地记录点 → 清理会话。关键点在于状态持久化和错误恢复。
- 用
OracleConnection的BeginTransaction()包裹 LogMiner 启动+查询+清理全过程,避免会话残留 - 记录最后成功处理的
END_SCN到本地文件或轻量数据库(如 SQLite),重启后从中断处继续 - 对
OPERATION = 'UPDATE'的记录,优先比对ROW_ID和OLD_ROWID(如有),而非依赖SQL_REDO解析 - 避免在 LogMiner 查询中使用
WHERE过滤大表——先查出所有变更再用 C# 筛选,否则性能暴跌
LogMiner 的解析粒度是 redo record,不是事务提交时间戳;一个事务可能分散在多个日志块里,COMMIT_SCN 并非绝对有序。这点最容易被忽略。











