客户端断连后无法自动重连,主因是SERVICE_NAME未动态注册、JDBC未配failover、Broker静态连接标识未更新及连接池缺乏验证机制。
客户端连接断开后无法自动重连?检查 SERVICE_NAME 是否动态注册
切换后应用连不上新主库,最常见的原因是客户端还在用旧的 service_name 连接老地址,而监听器没及时暴露新主库的服务名。data guard manager(dgmgrl)默认注册的服务名是 db_unique_name_dgmgrl,不是 oracle_sid 或静态服务名。
必须在切换完成后的**新主库上立即执行**:ALTER SYSTEM REGISTER;,强制将当前实例的 SERVICE_NAME 推送给监听器。否则 lsnrctl status 里看不到新主库对应的服务条目。
同时确认 listener.ora 中设置了正确的 GLOBAL_DBNAME:
GLOBAL_DBNAME = <db_unique_name>_DGMGRL</db_unique_name>
这个值要和 DGMGRL 内部注册名一致,否则 Broker 无法识别实例状态。
JDBC 应用连不上新主库?别硬写 IP+PORT,改用 SCAN 或 TNS Failover 配置
很多 JDBC 连接串直接写死 host=192.168.1.66:1521,切换后 DNS 没变、IP 没变,但服务已不在那台机器上——结果就是连接超时或卡住。
正确做法是让连接层具备故障感知能力:
- 使用 Oracle RAC 的 SCAN 地址(即使没用 RAC,也可模拟部署一个负载均衡 VIP)
- 或配置 TNS failover:在
tnsnames.ora中启用FAILOVER=on和LOAD_BALANCE=off,并把主备地址都列进ADDRESS_LIST - JDBC URL 中必须设置
oracle.net.CONNECT_TIMEOUT=10000(单位毫秒),否则网络探活会拖慢重试节奏 -
SERVICE_NAME必须设为db_unique_name对应的值(例如备库db_unique_name=stby,就填stby),不能填ORACLE_SID
Switchover 后应用仍往旧主库发请求?Broker 静态连接标识未更新
如果用了 DGMGRL 管理 Data Guard,切换后 DGMGRL 内部仍保留着旧的连接信息,下次执行 switchover 或 failover 时可能连错实例。
必须手动刷新每个数据库的 StaticConnectIdentifier 属性:
EDIT DATABASE 'old_primary_db' SET PROPERTY 'StaticConnectIdentifier' = '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=new_host)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=old_primary_db)))';
注意:这里的 old_primary_db 是数据库在 Broker 中的名称,不是 db_unique_name;HOST 和 SERVICE_NAME 要按新角色重新对齐。
漏掉这步,Broker 可能尝试用旧连接串去连已下线的实例,报错 ORA-12514: TNS:listener does not currently know of service requested in connect descriptor。
为什么有些应用“感觉不到切换”,有些却报大量连接异常?关键在连接池行为
连接池是否主动验证连接有效性,决定了业务能否平滑过渡:
- HikariCP 默认不校验空闲连接,需显式配置
connection-test-query=SELECT 1 FROM DUAL和validation-timeout=3000 - Tomcat JDBC Pool 需开启
testOnBorrow="true"+validationQuery="SELECT 1 FROM DUAL" - Oracle UCP(Universal Connection Pool)支持
enableImplicitCaching=true和自动重连,但前提是底层 TNS 配置已启用 failover
没有连接验证机制的应用,在切换瞬间会继续复用旧连接句柄,直到执行 SQL 时才报 ORA-03113: end-of-file on communication channel ——这不是 Data Guard 的问题,而是连接池没配合好。
最容易被忽略的一点:哪怕所有配置都对了,第一次连接失败后重试间隔仍由客户端驱动控制,比如 Oracle JDBC 的 oracle.net.RETRY_COUNT 和 RETRY_DELAY 默认是关闭的,得显式打开。











