hikaricp连接oracle 19c时tcp连接数居高不下,主因是oracle端sqlnet.expire_time=10分钟静默断连,而连接池未配置keepalivetime和connectiontestquery及时探测剔除失效连接,导致established僵尸连接堆积。

Java应用连接 Oracle 19c 时 TCP 连接数居高不下,**不是连接池没回收,而是连接被数据库端静默关闭后,连接池没及时感知并剔除**。常见现象是 netstat -an | grep :1521 显示大量 ESTABLISHED 状态连接长期不释放,但 HikariCP 的 active 数却很低——说明连接已失效,但池子还留着。
Oracle sqlnet.expire_time 主动断连未被连接池探测到
Oracle 19c 默认启用死连接检测:sqlnet.expire_time=10(单位分钟),即空闲超 10 分钟的 TCP 连接会被服务端发 RST 强制关闭。但 HikariCP 若未配置有效的心跳或验证机制,不会主动探测连接是否还活着。
- 连接归还池中时仍是“逻辑可用”状态,但底层 socket 已被 Oracle 关闭
- 下次取出该连接执行 SQL,触发
SQLRecoverableException: IO Error: Connection reset,此时才真正丢弃 - 这期间连接在 OS 层仍显示为
ESTABLISHED,直到 TCP keepalive 触发(默认 2 小时)才会转为CLOSE_WAIT
解决方法:在 HikariCP 配置中显式设置 keepaliveTime 和 connectionTestQuery:
config.setKeepaliveTime(300000); // 每 5 分钟发一次心跳
config.setConnectionTestQuery("SELECT 1 FROM DUAL");
HikariCP idleTimeout / maxLifetime 与 Oracle 参数错配
若 idleTimeout 或 maxLifetime 设得比 sqlnet.expire_time 大,就必然出现“僵尸连接”堆积。
-
idleTimeout必须 ,建议设为540000(9 分钟) -
maxLifetime同样不能超过 10 分钟,推荐1500000(25 分钟)仅适用于已禁用sqlnet.expire_time的场景;否则必须 ≤ 600000 - 检查数据库侧是否真启用了该参数:
SHOW PARAMETER sqlnet_expire_time(需查$ORACLE_HOME/network/admin/sqlnet.ora)
Oracle 用户 PROFILE 中 IDLE_TIME 限制被忽略
即使连接池做了超时控制,DBA 可能在用户 profile 中设置了 IDLE_TIME,比如 ALTER PROFILE DEFAULT LIMIT IDLE_TIME 30。Oracle PMON 会在空闲 30 分钟后直接 RST 断连,且不通知客户端。
- 该行为独立于
sqlnet.expire_time,优先级更高 - 验证方式:
SELECT LIMIT FROM DBA_PROFILES p JOIN DBA_USERS u ON p.PROFILE = u.PROFILE WHERE u.USERNAME = 'YOUR_USER' AND p.RESOURCE_NAME = 'IDLE_TIME' - 临时解法:
ALTER PROFILE DEFAULT LIMIT IDLE_TIME UNLIMITED;长期应协调 DBA 放宽或同步连接池策略
/dev/random 阻塞导致连接卡在建立阶段,间接拉长连接生命周期
Java 启动或首次连接 Oracle 时,ojdbc8 会调用 SecureRandom 生成密钥材料,默认读取 /dev/random。在熵不足的容器或云主机上,该调用可能阻塞几十秒甚至更久——连接没建完就被应用层超时丢弃,但 socket 可能已进入 SYN_SENT 或 ESTABLISHED 状态并滞留。
- 现象:
strace -e trace=open,read java ...可见卡在read("/dev/random", ...) - 修复方式(三选一):
– JVM 启动加-Djava.security.egd=file:/dev/./urandom
– 修改$JAVA_HOME/conf/security/java.security中securerandom.source
– 容器内挂载:ln -sf /dev/urandom /dev/random(需评估安全合规性)
真正难排查的是多种机制叠加:比如 sqlnet.expire_time=10 + IDLE_TIME=30 + idleTimeout=1800000 + /dev/random 阻塞——连接既建不稳,又死不干净,最终表现为 TCP 连接数缓慢爬升、难以回落。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











