odp.net连接需显式配置connection timeout和retry count才支持重试,connection timeout=15控制单次建连超时,retry count=3启用tcp层重试,connection lifetime=0避免连接池复用过期连接。

ODP.NET 连接字符串里必须加 Connection Timeout 和 Retry Count
ODP.NET 默认不会自动重连,断开后 OracleConnection.Open() 抛出异常就停了。要让底层尝试恢复连接,得靠连接字符串参数驱动。不配这两项,写再多重试逻辑都白搭。
关键参数如下:
-
Connection Timeout=15:控制单次连接建立最大等待秒数(不是重连总耗时) -
Retry Count=3:TCP 层级的底层重试次数,仅对网络闪断有效,对数据库服务宕机无效 -
Connection Lifetime=0:避免连接池返回已失效的物理连接(默认 0 表示不检查生存期)
示例连接字符串:Data Source=ORCL;User Id=scott;Password=tiger;Connection Timeout=15;Retry Count=3;Connection Lifetime=0;
手动重连必须捕获 OracleException 并检查 Number 错误码
ODP.NET 不提供“连接是否存活”的轻量探测方法,OracleConnection.State 在网络中断后可能仍为 Open,直接执行命令才会暴露问题。所以重连逻辑必须基于真实操作失败后的异常处理。
常见需重试的错误码:
-
Number == 3114:“Not connected to ORACLE”——典型会话已断 -
Number == 1033:“Oracle initialization or shutdown in progress”——库正在启停,可等几秒重试 -
Number == 12170:TNS:Connect timeout —— 网络层超时,配合Retry Count已覆盖
不要 catch Exception 或 InvalidOperationException,它们掩盖真实原因;也不要依赖 SqlException,ODP.NET 抛的是 OracleException。
应用层重试需用指数退避 + 最大尝试次数限制
连接字符串里的 Retry Count 只管 TCP 握手,业务层要应对数据库服务重启、RAC 实例切换、防火墙中断等场景,必须自己实现重试。无脑循环重试会压垮连接池或触发 Oracle 的登录限流(如 FAILED_LOGIN_ATTEMPTS)。
建议结构:
- 最多重试 3 次(含首次),超过立即失败
- 每次间隔按 2ⁿ 秒递增:第 1 次失败后等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒
- 每次重试前调用
connection.Close()再新建OracleConnection实例,别复用旧对象 - 若重试中遇到
ORA-01017(用户名密码错)或ORA-12514(SID 不存在),立刻终止,这类错误不会随重试消失
连接池启用时 ClearAllPools() 要慎用
很多人在重连失败后调用 OracleConnection.ClearAllPools() 强制清空连接池,以为能解决“脏连接”问题。但这个操作是进程级全局行为,会中断所有正在使用的连接,导致并发请求大面积失败。
更安全的做法:
- 只对当前失败连接调用
connection.Dispose(),让连接池自动标记该池为“可疑” - 下次从池中获取连接时,ODP.NET 会隐式做一次快速 ping(发个空包),若失败则丢弃并新建物理连接
- 真需要强制刷新,改用
OracleConnection.ClearPool(pool),传入当前连接对象,只清对应连接字符串的池
连接池本身是双刃剑:它加速连接复用,但也让失效连接滞留更久。ODP.NET 19c+ 版本支持 Validate Connection=true 参数,开启后每次取连接都会验证,但会增加约 5–10ms 延迟,得权衡。











