oracle data guard切换后客户端自动重连需依赖service_name动态绑定与数据库角色联动,而非address_list轮询或连接池重试;核心是通过dbms_service在primary启动服务、standby停用服务,并配合taf或ucp实现透明故障转移。

Oracle Data Guard 切换后客户端不能自动重连,除非你提前做了明确配置——不是靠连接池“重试”就能解决的,而是必须让客户端感知不到切换发生,或至少让重连逻辑指向新主库。
tnsnames.ora 配置 ADDRESS_LIST 多地址轮询失效的原因
很多人把两个数据库 IP 写进 ADDRESS_LIST,以为客户端会自动尝试下一个地址。但 Oracle 客户端默认只用第一个可连上的地址,后续地址仅在第一个完全不可达(如端口未监听)时才启用,而 DG 切换后旧主库往往仍监听 1521 端口,只是拒绝新连接或返回 ORA-16000(database open for read-only access),此时客户端不会 fallback 到第二个地址。
-
ADDRESS_LIST不处理角色变更,只做网络层连接尝试 - 旧主库切换为 standby 后仍运行监听器,
TNS-12514或ORA-16000错误不会触发地址切换 - Java 应用常用 HikariCP/DBCP 连接池,其“重连”默认重试原 URL,不解析 tnsnames 中多个 ADDRESS
真正起作用的是 SERVICE_NAME + 数据库侧动态启停服务
核心思路是:让所有客户端始终连同一个 SERVICE_NAME(比如 myapp),而这个 service 只在当前 primary 上运行,standby 上停掉。切换后,新 primary 自动启动该 service,旧 primary 自动停止——客户端无需改任何配置,只要重连就自然落到新主库。
- 在 primary 执行:
DBMS_SERVICE.CREATE_SERVICE('myapp', 'myapp'),再DBMS_SERVICE.START_SERVICE('myapp') - 创建 startup 触发器,确保每次数据库启动时检查
v$database.database_role,只在PRIMARY角色下启动 service - standby 侧无需手动操作,DG 日志同步会自动 replay trigger 和 service 状态变更
- 客户端 tns 配置中
CONNECT_DATA.SERVICE_NAME固定写myapp,不写实例名或 SID
Java 应用连接字符串里必须启用 TAF 或 UCP 故障转移
即使 tns 配置正确,JDBC 默认行为仍是单次连接失败就抛异常。要实现“查询被阻塞几秒后自动续上”,必须显式启用透明应用故障转移(TAF)或使用 Oracle Universal Connection Pool(UCP)。
- 传统 thin driver 不支持 TAF,必须用
oracle.jdbc.driver.OracleDriver(oci mode)或 19c+ 的oracle.jdbc.driver.T4CConnection并配FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=5)(DELAY=2) - 更推荐 UCP:设置
connectionFactory.setURL("jdbc:oracle:thin:@MYAPP"),并开启setFastConnectionFailoverEnabled(true),它会监听 Oracle RAC/ADG 的 service 事件 - Spring Boot + Oracle JDBC 21c 起支持
spring.datasource.hikari.data-source-properties.oracle.jdbc.fcf-enabled=true,但需搭配 Broker 和 observer 才生效
Broker + FSFO observer 缺失导致自动重连形同虚设
很多团队配了 tns 和 service,却没部署 observer,结果 failover 触发后没有进程通知客户端 service 已迁移——客户端仍在连旧地址,直到连接超时或应用重启。
-
START OBSERVER必须在独立主机执行,且 observer 进程常驻;远程调用或脚本里临时起 observer 无效 - observer 日志路径固定为
$ORACLE_HOME/rdbms/log/drc*.log,故障时第一眼要看这里有没有Failover initiated或Observer lost contact - 若用云环境(如 OCI Exadata),确认 observer 主机能双向访问主备库的
StaticConnectIdentifier,常见坑是安全组只放行 1521,漏了 broker 默认的 8888 或自定义端口
最容易被忽略的一点:service 名称必须和 tns 中的 SERVICE_NAME 完全一致(含大小写),且不能与数据库默认 service(如 orcl.example.com)冲突;一旦冲突,DBMS_SERVICE.START_SERVICE 会静默失败,查 v$active_services 才能发现没起来。











