connecttimeout仅控制tcp建连,不解决dns解析失败或rac节点失效;需配合oracle.net.connect_timeout(覆盖dns+tcp)、retry_count和retry_delay实现scan高可用,连接池还需配置有效性校验。
connecttimeout参数只控制tcp建连,不解决dns或rac节点失效
connecttimeout 是 jdbc url 中最常被误用的超时参数之一。它仅作用于 tcp 三次握手阶段:从发起 connect() 系统调用开始,到收到 syn-ack 或超时为止。一旦 tcp 连接建立成功(哪怕 oracle 监听器还没响应),这个参数就不再生效。
常见错误现象包括:
- 写错 SCAN 域名,DNS 解析失败,但
connectTimeout完全不触发(因为根本没走到 TCP 层) - SCAN 返回了某个已宕机节点的 VIP,TCP 能连上(监听端口开着),但后续认证卡住 —— 此时
connectTimeout已结束,实际阻塞在logon()阶段 - Oracle 实例崩溃但监听仍在,连接能建,但执行
SELECT 1 FROM DUAL一直挂起 —— 这是socketTimeout的职责范围
所以单靠 connectTimeout=5000 并不能覆盖“连接不可用”的全部场景。
必须配合 oracle.net.CONNECT_TIMEOUT 才能覆盖DNS+TCP全过程
Oracle JDBC 驱动内部有两套超时逻辑:JDBC 标准层(connectTimeout、socketTimeout)和 Oracle 私有网络层(oracle.net.CONNECT_TIMEOUT、oracle.net.RETRY_COUNT)。后者才是真正面向 RAC 和 SCAN 场景设计的。
oracle.net.CONNECT_TIMEOUT 单位是毫秒,它会同时约束 DNS 查询耗时 + TCP 连接耗时。若 DNS 解析慢或返回多个 A 记录,驱动会逐个尝试,直到总耗时超限才放弃。
使用时注意:
- 必须写在 TNS 描述符格式的 URL 末尾,例如:
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=my-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))(oracle.net.CONNECT_TIMEOUT=10000) - 不能和标准
connectTimeout混用,否则行为不可预测(驱动优先采用私有参数) - 值设太小(如 1000)可能导致 DNS 轮询来不及完成就被中断;设太大(如 30000)又会拖慢故障感知
重试不是自动发生的,得靠 oracle.net.RETRY_COUNT + RETRY_DELAY
即使你用了 SCAN 和 TNS 描述符,JDBC 驱动默认也只尝试一次 —— 它不会自动重选另一个 SCAN VIP 并重连。要启用重试,必须显式配置两个私有参数:
-
oracle.net.RETRY_COUNT=2:表示最多重试 2 次(即总共最多连 3 次:首次 + 2 次重试) -
oracle.net.RETRY_DELAY=1000:每次重试前等待 1 秒,避免对集群造成密集探测压力
关键点在于:重试动作发生在单次 getConnection() 调用内,不是连接池层面的“获取新连接”。也就是说,如果第一次连的是 VIP-A 失败,第二次会 DNS 重解析拿到 VIP-B 再试,而不是复用旧连接。
示例完整 URL:jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=my-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))(oracle.net.CONNECT_TIMEOUT=10000)(oracle.net.RETRY_COUNT=2)(oracle.net.RETRY_DELAY=1000)
连接池里配 SCAN,光靠 URL 不够,还得开连接验证
HikariCP 或 Druid 这类连接池会缓存物理连接。即便你 URL 配了重试,池中已有连接一旦指向的 RAC 节点下线,后续借用该连接仍会失败 —— 因为重试机制只在 getConnection() 初始创建时触发,不作用于池中已存在的连接。
必须补上连接有效性校验:
- HikariCP 推荐用
connection-test-query=/* ping */ SELECT 1 FROM DUAL(注意注释写法,避免被 Oracle 优化器误判) - 同时设置
validation-timeout=3000(校验 SQL 最长允许耗时)和idle-timeout=600000(空闲连接 10 分钟后强制校验) - 避免用
test-on-borrow=true,高并发下性能损耗大;改用test-on-return=false+ 合理的idle-timeout更稳妥
漏掉这步,URL 里所有重试参数都只是纸上谈兵。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











