tnsnames.ora中LOAD_BALANCE=ON必须置于ADDRESS_LIST内,否则无效;JDBC需显式传参load_balance=on(小写);只读路由需客户端声明ApplicationIntent=ReadOnly或oracle.net.READ_ONLY=true;每个ADDRESS须单独配置CONNECT_TIMEOUT。
tnsnames.ora 中 LOAD_BALANCE=ON 必须嵌套在 ADDRESS_LIST 内
客户端连接始终打到第一个地址,不是监听器没配好,而是 load_balance=on 放错了位置。oracle 客户端只识别写在 address_list 括号内的该参数,其他任何层级(比如 description 顶层或同级)都会被忽略。
常见错误写法:(DESCRIPTION=(LOAD_BALANCE=ON)(ADDRESS=...)(ADDRESS=...)) —— 这完全无效。
正确结构必须是:(ADDRESS_LIST=(LOAD_BALANCE=ON)(ADDRESS=...)(ADDRESS=...))
- 一个
DESCRIPTION可含多个ADDRESS_LIST,但负载均衡只在单个ADDRESS_LIST内部生效,跨 list 不轮询 - 客户端每次新建连接时随机选一个
ADDRESS,不适用于已建立的长连接(如 SQL*Plus 会话) - 短连接场景(如 Web 应用、批处理脚本)效果最明显
JDBC 连接需显式传参 load_balance=on(小写 on)
Java 应用即使 tnsnames.ora 配对了,负载均衡仍不生效,大概率是 JDBC URL 里参数写错了。Oracle JDBC 驱动对 load_balance 参数严格区分大小写,且只接受字符串 on。
正确示例:jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=TCP)(HOST=db1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=db2)(PORT=1521))))?TNS_ADMIN=/path/to/network/admin&load_balance=on
- 错误写法包括:
&load_balance=ON、&load_balance=true、&load_balance=1 - 该参数仅影响客户端解析
tnsnames.ora的行为,不改变服务端监听逻辑 - 若使用连接池(如 HikariCP),确保连接字符串中包含该参数,而非依赖池配置覆盖
备库连接必须声明 ApplicationIntent=ReadOnly 或 oracle.net.READ_ONLY=true
Oracle Data Guard 的只读路由机制不会自动把请求发到备库——它依赖客户端显式声明读意图。主库监听器中的 READ_ONLY_ROUTING_LIST 配置只在收到带读标识的连接请求时才触发路由。
.NET 应用需在连接字符串中加:ApplicationIntent=ReadOnly
JDBC 应用需加:oracle.net.READ_ONLY=true
- 该机制要求 Oracle Net Services 12c 及以上版本;11g 不支持,强行配置无效果
-
READ_ONLY_ROUTING_LIST必须在主库的listener.ora中配置,格式为:(READ_ONLY_ROUTING_LIST=((PRIMARY_ROLE)(SERVICE_NAME=report)(INSTANCE_NAME=orcl_standby)(SERVER=DEDICATED))) - 备库监听器本身无需特殊配置,但需确保其服务名(如
report)已注册并处于 READY 状态(可通过lsnrctl services验证)
每个 ADDRESS 必须单独配 CONNECT_TIMEOUT,否则故障转移卡死
开了 FAILOVER=ON 却发现连接失败后等 20–30 秒才切下一个地址?这不是配置失效,而是 Oracle 默认依赖 TCP 层超时,不会主动中断连接尝试。
补救措施:为每个 ADDRESS 显式设置 CONNECT_TIMEOUT,单位秒,例如:(ADDRESS=(PROTOCOL=TCP)(HOST=db1)(PORT=1521)(CONNECT_TIMEOUT=10))
-
CONNECT_TIMEOUT必须写在每个ADDRESS括号内,不能放在外层 -
RETRY_COUNT和RETRY_DELAY控制重试次数与间隔,但不能替代CONNECT_TIMEOUT—— 前者在连接建立失败后起作用,后者控制单次连接尝试的等待上限 - 如果某节点宕机但监听器进程仍在(如数据库崩溃但 listener 还活着),
CONNECT_TIMEOUT是唯一能避免长时间阻塞的手段
ADDRESS_LIST + LOAD_BALANCE=ON,所有流量仍默认走第一个地址。路由决策完全由客户端驱动,服务端只是被动响应。


















