Oracle RAC连接池必须显式配置所有SCAN IP,禁用DNS缓存,并启用test-on-borrow与Oracle专用校验器,否则failover失败;C3P0/Druid无法替代TAF,业务需捕获SQLRecoverableException并重试逻辑。
Oracle RAC 连接池必须显式配置多个 SCAN IP,否则 failover 会失败
oracle rac 的 scan(single client access name)本质是 dns 轮询返回的多个 vip,但 jdbc 驱动默认只解析并缓存第一个 ip。如果该节点宕机,connection 建立阶段就卡住或抛 java.sql.sqlrecoverableexception: io 错误:the network adapter could not establish the connection,根本等不到连接池的重试逻辑生效。
实操建议:
- 在 JDBC URL 中**显式列出所有 SCAN IP(而非只写 SCAN 域名)**,例如:
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.5.101)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.5.102)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.5.103)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=orcl))) - 禁用 DNS 缓存:JVM 启动参数加
-Dnetworkaddress.cache.ttl=0 -Dnetworkaddress.cache.negative.ttl=0,避免本地 DNS 解析结果长期滞留 - 不要依赖
oracle.jdbc.fanEnabled=true—— 它仅对 Oracle 官方 UCP 有效,C3P0/Druid 不识别该参数
Druid 的 connection-error-retry-attempts 对 RAC 无效,得靠 valid-connection-checker + test-on-borrow
Druid 的 connection-error-retry-attempts 只在获取连接时发生“连接池内部异常”(比如连接被意外关闭)才触发重试,而 RAC 节点不可达属于网络层失败,该参数完全不生效。
真正起作用的是连接校验机制:
- 必须启用
test-on-borrow=true,否则坏连接会被直接返回给业务 - 搭配使用 Oracle 专用校验器:
valid-connection-checker-class-name=com.alibaba.druid.pool.vendor.OracleValidConnectionChecker,它执行SELECT 1 FROM DUAL而非简单 socket ping,能真实探测到实例是否在线 -
validation-query-timeout=3建议设为 3 秒,避免单个节点超时拖慢整个连接获取流程 - 禁用
test-while-idle—— RAC 场景下空闲连接频繁校验反而增加 SCAN 负载,且无法覆盖故障刚发生时的窗口期
C3P0 的 acquireRetryAttempts 和 acquireRetryDelay 只控制初始建连,不是 failover 机制
很多人以为把 acquireRetryAttempts=30、acquireRetryDelay=1000 就能实现自动切换节点,其实这只是在应用启动时反复尝试连同一个地址(即 URL 里第一个 ADDRESS)。一旦连接池初始化成功,后续借连接就不再走这套重试逻辑。
正确做法是结合 Oracle 自身的客户端重试:
- 在 JDBC URL 中加入
(FAILOVER=on)(RETRY_COUNT=3)(RETRY_DELAY=1),这是 Oracle JDBC Thin 驱动原生支持的 TNS 描述符参数 - 确保驱动版本 ≥ 12.1 —— 旧版(如 11.2)对
RETRY_COUNT支持不完整,可能静默忽略 - C3P0 层只需配
checkoutTimeout=5000,防止业务线程无限等待;acquireRetryAttempts保持默认 30 即可,没必要调高
Druid/C3P0 都无法替代 Oracle RAC 的 TAF(Transparent Application Failover)
TAF 是 Oracle 实例级故障转移,要求连接建立时就协商好备用实例,并在运行中自动迁移活跃事务。而 C3P0/Druid 所有重试都发生在连接获取阶段,已建立的连接一旦所在节点宕机,就会直接报错,不会自动切到其他节点继续执行。
这意味着:
- 业务代码必须捕获
SQLRecoverableException并主动重试整个业务逻辑(不是重试单条 SQL) - 不能依赖连接池“自动续命”,尤其长事务、批处理场景,TAF 不生效时必须设计补偿或降级路径
- 监控上要区分两类失败:建连失败(可由连接池缓解) vs 运行时连接中断(必须业务兜底)
SCAN IP 列表、驱动参数、校验方式这三者缺一不可,少配一个,RAC 的高可用在 Java 应用侧就形同虚设。










