“Connection request timed out”真实含义是连接池已满导致新请求阻塞等待超时,根本原因是连接泄漏、连接字符串不一致致池分裂、关键参数未显式配置及Max Pool Size超Oracle PROCESSES限制。
这个错误不是网络不通或数据库拒绝连接,而是连接池已满、新请求在 open() 调用处阻塞等待——直到 connection timeout 秒后才抛异常。典型表现是:v$session 中大量 status = 'inactive'、应用会话数卡死在 max pool size 值、重启后立刻恢复但几小时内复现。
根本原因几乎总是连接泄漏:未释放的 OracleConnection 或未关闭的 OracleDataReader 占着连接不归还。GC 不会自动回收它们,ODP.NET 只认 Dispose() 或 Close()。
using (var conn = new OracleConnection(cs)) { ... } 是最安全写法,但提前 return、throw 或 goto 会跳过 Dispose
try { cmd.ExecuteReader(); } catch { log.Error(e); return; } —— 异常路径没释放连接,极常见OracleConnection 存在类字段或静态变量里,长期持有ODP.NET 判断是否复用连接,靠的是连接字符串**完全相同的字面量**。大小写、空格、分号位置、换行符不同,都会创建独立连接池。后果是:本该共享 100 个连接的流量,被切成两个池各占 50,但每个池都卡在 Max Pool Size=100 上限,NumberOfFreeConnections 持续为 0。
$"Data Source={host};" 容易引入不可见字符Max Pool Size=100 ✅,Max Pool Size = 100 ❌(参数被忽略)OracleConnection 实例指向同一数据库却显示不同池名(如 pool-1 和 pool-2)以下三项不显式配置,性能优化基本无效,尤其在高并发下:
Pooling=true:必须显式写,某些旧部署环境默认为 false
Statement Cache Size=50:默认为 0(禁用),启用后显著减少硬解析;值超过 200 可能拖慢查找Metadata Performance=Enabled:高频租户分表场景必开,跳过首次 DML 时查 all_constraints 等系统表的开销Validate Connection=true:每次取连接前轻量 ping,规避防火墙断连,但增加约 1–2ms 开销Connection Timeout=15:控制“等连接”的最长时间,设太小导致频繁报错,设太大让故障响应变慢注意:Connection Lifetime=60 是性能杀手——它让连接取出后存活满 60 秒就标记过期,归还时不进池,等于废掉复用能力。生产环境应设为 0。
每个 ODP.NET 物理连接至少占用一个 Oracle PROCESS。若数据库 PROCESSES=150,而你设 Max Pool Size=200,实际可用连接顶多 120–130 个(需预留后台进程)。超出后会出现 ORA-12519 报错,而非连接池耗尽。
SELECT VALUE FROM V$PARAMETER WHERE NAME = 'processes';
Max Pool Size = PROCESSES × 0.7(例如 150 → 100)appsettings.json 里写 "Max Pool Size": 100——JSON 解析后变成整数,ODP.NET 只认字符串形式参数Min Pool Size 不维持常驻连接,仅影响冷启动,值过大反而浪费资源真正卡住等待时间的,从来不是池大小本身,而是泄漏点没暴露、池被割裂、或服务端资源已到硬限——这些细节比调数字更难盯住。