必须由应用层或中间件驱动同步,因Oracle无原生CDC或binlog供Redis直连;常用捕获方式包括LogMiner、GoldenGate、触发器队列和轮询;Redis写入需避开事务内操作、避免全量覆盖、级联清理关联缓存;.NET中应分层封装事件驱动模型并实现失败重试。

不能靠 Redis 自己监听 Oracle 变更,必须由应用层或中间件主动驱动同步逻辑。 Oracle 没有类似 MySQL 的 binlog 机制供 Redis 直接消费,也没有原生 CDC(Change Data Capture)对 Redis 开放接口。所有“自动同步”方案,本质都是在 Oracle 端埋点、捕获变更,再推到 Redis —— 这个过程必然引入额外组件或业务侵入。
Oracle 端怎么捕获数据变更
Oracle 自身提供几种可行路径,但各有约束:
-
DBMS_LOGMNR:可解析归档日志,但需开启补充日志(ADD SUPPLEMENTAL LOG DATA),且对 RAC、PDB 支持有限;解析结果是 SQL 文本,需自行映射为 Redis key 结构 -
Oracle GoldenGate:企业级方案,支持实时捕获并投递到 Kafka/HTTP/文件等目标,但部署重、授权贵,不适合中小项目 - 触发器 + 队列表(
USER_QUEUE_TABLES):在关键表上建AFTER INSERT/UPDATE/DELETE触发器,把变更写入 AQ 队列;.NET 后台用Oracle.ManagedDataAccess.Client轮询或监听队列。轻量但会增加 DML 延迟,且需处理触发器异常回滚问题 - 定时轮询
SCN或时间戳字段:最简单,比如查LAST_MODIFIED_TIME > @lastSyncTime,但无法捕获 DELETE,延迟高,对 Oracle 表加索引压力明显
Redis 缓存更新该用哪种方式写入
直接用 StackExchange.Redis 写入时,注意三个实际卡点:
- 不要在事务中调用
IDatabase.StringSet():Oracle 事务提交前 Redis 就写入,会导致脏读;必须等 OracleCOMMIT成功后再触发 Redis 更新 - 避免用
SET覆盖整个对象:若只改了用户邮箱,却把整个UserJSON 重刷进 Redis,浪费带宽且可能覆盖并发修改;建议用Hash存储,仅HSET user:123 email new@x.com - DELETE 同步不能只删 key:关联缓存如
user:123:orders、user:123:profile也要一并清理,否则产生陈旧数据;推荐用KEYS user:123*+DEL组合,但生产环境禁用KEYS,应改用SCAN分批清理
.NET 6 中如何组织同步代码结构
别把同步逻辑散落在 Service 方法里。推荐分层封装:
- 定义变更事件类:
OracleChangeEvent,含TableName、Operation(INSERT/UPDATE/DELETE)、PrimaryKey、NewValue、OldValue - 建
IObservable接口,上游(触发器队列消费者 / LogMiner 解析器)作为> IObserver推送事件 - 下游注册
RedisCacheSyncHandler,根据TableName映射到对应CacheKeyBuilder,生成如user:{id}、order:{id}:items等 key,并调用IDatabase执行原子操作 - 所有 Redis 操作包裹
try/catch,失败时记录OracleChangeEvent到本地重试表(如cache_sync_failures),避免丢变更
真正难的不是“怎么写进 Redis”,而是“怎么确保 Oracle 提交成功后,Redis 一定写入成功”。网络分区、Redis 临时不可用、序列化失败——这些场景下,必须有可追溯、可补偿的机制,而不是依赖一次性的 try-catch。











