odp.net不支持fcf,仅能通过taf实现高可用,需服务端启用failover_type=select、连接串设failover=true并禁用load_balance,否则taf失效。

UCP 不支持 .NET,必须用 ODP.NET + Transparent Application Failover(TAF)替代 FCF。Oracle 官方从未为 .NET 提供过 Fast Connection Failover(FCF)支持——FCF 是 Java UCP / JDBC 驱动专属机制,依赖 ONS 事件监听和池级主动清理,而 ODP.NET 的设计模型完全不同。
为什么 oracle.jdbc.fanEnabled=true 在 .NET 里完全无效
这不是配置写错,而是根本不存在对应实现:oracle.jdbc.fanEnabled 是 JDBC 驱动的属性名,ODP.NET 使用的是完全独立的连接字符串参数体系。你在 ConnectionString 里加 fanEnabled=true 或类似键值,ODP.NET 会直接忽略,不报错也不生效。
- ODP.NET 没有内置 ONS 客户端,无法订阅 FAN 事件
- ODP.NET 连接池不响应服务端推送的 down/up 通知,没有
setFastConnectionFailoverEnabled()这类 API - 所有“高可用”行为都靠 TAF(Transparent Application Failover)或 connect-time failover 实现,二者均为被动重试机制,非事件驱动
ODP.NET 中真正可用的高可用方案:TAF 配置要点
TAF 是 ODP.NET 唯一原生支持的运行时故障转移机制,它在连接已建立后监听实例状态变化,并在 SELECT 执行中自动重连到存活节点。但启用前提是服务端 RAC service 明确启用了 TAF 支持(srvctl config service 中显示 FAILOVER_TYPE=SELECT)。
- 连接字符串中必须显式指定
Failover=true,仅靠LOAD_BALANCE=true不触发 TAF - service 名必须与 RAC 中定义的完全一致(大小写敏感),且该 service 必须通过
srvctl add service -faiover_type SELECT创建 - 避免混用 TAF 和 connect-time failover:不要在 tnsnames.ora 描述符中同时写
FAILOVER=ON和FAILOVER_MODE,否则可能干扰 TAF 路由逻辑 - TAF 只对
SELECT有效;DML 操作中断后不会自动重放,需应用层捕获OracleException并重试
示例连接字符串(使用 SCAN):Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myrac-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=my_service)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC))));User Id=myuser;Password=mypass;Failover=true;
tnsnames.ora 配置陷阱:LOAD_BALANCE=ON 会破坏 TAF 行为
很多人误以为 LOAD_BALANCE=ON 能提升可用性,实际在 TAF 场景下它会导致连接被随机绑定到某个实例,削弱 TAF 的故障感知能力——因为 TAF 依赖连接初始建立时的 service 上下文来识别 failover group,而负载均衡打乱了这个上下文一致性。
- tnsnames.ora 中应禁用
LOAD_BALANCE和FAILOVER参数,只保留基础地址与 service 配置 - 正确写法示例:
(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myrac-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=my_service))) - 如果必须用多地址 fallback(如 Data Guard 场景),改用
DESCRIPTION_LIST+FAILOVER=ON,但这属于 connect-time failover,与 TAF 互斥,不能共存
最易被忽略的一点:TAF 不是开个开关就自动生效的黑盒。它要求客户端和服务端严格对齐 FAILOVER_TYPE、METHOD、RETRIES 等参数,且 Oracle Net 日志(sqlnet.ora 中设置 TRACE_LEVEL_CLIENT=16)是唯一能验证 TAF 是否真正在工作的依据——没日志,就等于没启用。











