taf在java中不会自动生效,必须服务端service配置failover_type=select、客户端tnsnames.ora写全failover_mode块(含type=select/method=basic/retries/delay)、jdbc url引用该别名(不可用easy connect),三者缺一不可。

TAF 在 Java 应用里不会自动生效,光改 JDBC URL 或调用 setFailoverEnabled(true) 没用——必须同时满足服务端 SERVICE 配置、客户端 TNS 描述符、JDBC 连接串三者协同,缺一不可。
tnsnames.ora 必须写全 FAILOVER_MODE 块,不能只靠 FAILOVER=ON
很多人在 tnsnames.ora 里只写多个 ADDRESS 并加 FAILOVER=ON,这只能实现建连时失败换地址(Connect-time Failover),对已建立连接后的实例宕机完全无效。Java 程序一旦连上某个节点,该节点挂了就会直接抛 SQLException,比如 ORA-03113 或 IO Error: Connection reset。
真正启用 TAF 需要在 CONNECT_DATA 下显式声明完整 FAILOVER_MODE:
(DESCRIPTION =
(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 = 5)
)
)
)
-
TYPE = SELECT是关键:只有它能让中断的SELECT查询在重连后继续返回剩余结果;TYPE = SESSION只重建会话,不续查 -
METHOD = BASIC是 ojdbc8+ 唯一支持的模式;PRECONNECT已废弃,设了也无效,且容易和连接池(如 HikariCP)冲突引发ORA-12519 -
RETRIES和DELAY要合理:太小(如DELAY=1)可能被监听器限流;太大(如DELAY=30)会让应用卡顿明显
JDBC URL 必须引用 tnsnames 别名,不能用 Easy Connect 格式
Oracle JDBC 驱动(ojdbc8.jar 或更高)只在解析 tnsnames.ora 时读取 FAILOVER_MODE。如果你的 JDBC URL 写成 jdbc:oracle:thin:@//rac1-vip:1521/myapp 这类 Easy Connect 形式,FAILOVER_MODE 完全被忽略,TAF 不启动。
正确做法是:
- 确保
tnsnames.ora文件路径被oracle.net.tns_adminJVM 参数指定,例如:-Doracle.net.tns_admin=/path/to/tns - JDBC URL 使用别名:
jdbc:oracle:thin:@myapp_alias(其中myapp_alias是tnsnames.ora中定义的名称) - 如果坚持用内联描述符,必须把整个
DESCRIPTION嵌入 URL,并显式带上FAILOVER=true开关:
jdbc:oracle:thin:@(DESCRIPTION=(FAILOVER=true)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=rac1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=rac2)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=myapp)(FAILOVER_MODE=(TYPE=select)(METHOD=basic)(RETRIES=3)(DELAY=1))))
服务端 SERVICE 必须用 srvctl add service 注册并启用 FAILOVER_TYPE=SELECT
TAF 不是纯客户端行为。服务端没配好,客户端再怎么写参数都白搭。常见错误是只用静态注册(SID_LIST)或只注册了 SERVICE_NAME 但没启用故障转移属性。
必须用 srvctl 创建 service,并指定 -e SELECT:
$ srvctl add service -d racdb -s myapp -r "rac1,rac2" -e SELECT -m BASIC -w 5 -z 3 $ srvctl start service -d racdb -s myapp
-
-e SELECT对应客户端的TYPE = SELECT,这是 SELECT 语句可重放的前提 -
-r列出的是首选实例(负载均衡目标),不是 failover 备选列表;failover 自动发生在 RAC 内部,无需手动指定“备节点” - 确认 service 已注册成功:
srvctl config service -d racdb -s myapp,输出中应含Failover type: SELECT - 不要在
listener.ora的SID_LIST里配GLOBAL_DBNAME,否则会禁用 TAF
Java 代码里别碰 setFailoverEnabled(true),异常必须显式捕获
OracleDataSource.setFailoverEnabled(true) 在 ojdbc8+ 中已被标记为 @Deprecated,调用它既不报错也不生效——TAF 是 Oracle Net 层特性,驱动只负责透传连接串参数,不自己实现重连逻辑。
TAF 生效时,应用不会“无感”,而是会在故障瞬间抛出明确异常:
- 典型异常类型:
java.sql.SQLRecoverableException,SQLState 为08006 - 常见 Oracle 错误码:
ORA-03113、ORA-03114、ORA-1012 - 这些异常必须由业务代码捕获并重试查询;不处理,线程就直接退出,TAF 形同虚设
- DML 操作(
INSERT/UPDATE)不支持重放,TAF 触发后未提交事务会回滚,应用需自行判断是否重试
最容易被忽略的一点:TAF 只在 RAC 或 Data Guard 主备切换场景下起作用,单实例数据库宕机不会触发任何故障转移行为。











