jdbc thin 连 oracle 19c rac 时 taf 默认不生效,必须在连接 url 中显式配置 failover=true 和完整 failover_mode 参数,且服务端 service 需启用对应 failover_type,否则客户端配置无效。

Java 应用连 Oracle 19c RAC 时,TAF 默认不生效
直接结论:JDBC Thin 模式下,FAILOVER=ON 或只写多个 ADDRESS 完全没用——连接建好后实例挂了,应用立刻收到 ORA-03113 或 IO Error: Connection reset,不会自动切到其他节点。
根本原因在于:Oracle 的 TAF 是 Oracle Net 层特性,不是 JDBC 驱动自己实现的逻辑。ojdbc8+ 驱动只负责把连接串里的参数透传给底层网络栈,不参与重连决策。
-
setFailoverEnabled(true)在 ojdbc8+ 中已@Deprecated,调用它静默无效 - tnsnames.ora 文件配置对 Java 应用无意义(除非你用 OCI 模式且本地装了 Oracle Client)
- 服务端未启用对应 service 的
FAILOVER_TYPE=SELECT或SESSION,客户端加再多参数也白搭
必须在 JDBC 连接串里显式声明 FAILOVER_MODE
Java 端唯一生效方式是把完整 TAF 参数塞进连接 URL,且所有字段缺一不可:
-
FAILOVER=true:总开关,不设它,整个FAILOVER_MODE被忽略 -
FAILOVER_MODE=(TYPE=select)(METHOD=basic)(RETRIES=3)(DELAY=2):四个参数必须全写,括号和等号不能少空格 -
TYPE=select才能续查(仅限 SELECT),TYPE=session只重建会话,DML 一律回滚(报ORA-25402) -
METHOD=basic是 ojdbc8 唯一支持的模式;preconnect已废弃,设了也不起作用
正确示例:jdbc:oracle:thin:@(DESCRIPTION=(FAILOVER=true)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=rac1-vip)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=rac2-vip)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=myapp)(FAILOVER_MODE=(TYPE=select)(METHOD=basic)(RETRIES=3)(DELAY=2))))
服务端 SERVICE 必须匹配 TYPE 配置
TAF 实际是否触发,最终由服务端定义的 FAILOVER_TYPE 决定。客户端连接串只是“请求”,服务端不认,请求就丢弃。
- 查当前 service 的 failover 类型:
SELECT NAME, FAILOVER_TYPE, FAILOVER_METHOD, FAILED_OVER FROM GV$ACTIVE_SERVICES; - 如果返回
FAILOVER_TYPE是NONE或空,说明服务没开 TAF - 用
srvctl重建 service 并指定类型(以select为例):srvctl modify service -d orcl -s myapp -f -y SELECT -e SESSION -m BASIC -z 3 -w 2 -
-y SELECT对应客户端TYPE=select;-e SESSION是故障后保持会话状态(非必须但建议)
注意:srvctl modify service 修改后需重启 service 生效:srvctl stop service -d orcl -s myapp && srvctl start service -d orcl -s myapp
应用层必须捕获并处理 TAF 切换异常
TAF 不是“无感”。连接断开瞬间,正在执行的语句一定抛异常,应用不 catch 就直接 crash。
- 典型异常信号:
SQLException.getSQLState()返回08006(connection exception)
或getErrorCode()返回3113、3114、1012 - SELECT 场景下,
TYPE=select成功时,ResultSet会继续返回剩余数据,但游标必须是HOLD_CURSORS_OVER_COMMIT模式(JDBC 默认是CLOSE_CURSORS_AT_COMMIT) - 事务中发生故障,无论 TYPE 是什么,未提交的 DML 全部回滚,应用需自行重试业务逻辑
最容易被忽略的一点:TAF 切换过程本身不保证幂等。如果你的代码在 catch 块里盲目重试 INSERT,可能造成重复写入——得靠应用层加幂等键或去重逻辑兜底。











