ADO.NET 默认启用连接池,但要求连接字符串完全一致(含大小写、空格、分号),否则视为不同池;Close()/Dispose() 仅归还连接至池,不立即断开网络;池大小、超时等参数直接影响错误类型与性能。

连接池不是自动开启的,得显式启用
ADO.NET 默认开启连接池,但前提是连接字符串完全一致——包括大小写、空格、额外分号。哪怕多一个 Pooling=true; 或少一个 Connection Timeout=30;,都会被视为不同池。常见错误是开发环境关了池(加了 Pooling=false;)测试完就忘了删,上线后扛不住并发。
实操建议:
- 用
SqlConnection.ConnectionString检查运行时实际值,别只看代码里写的 - 连接字符串中避免动态拼接用户名/密码;若必须,确保所有路径拼出的字符串字面量 100% 相同
- 不要在连接字符串里混用等价写法,比如
Initial Catalog=abc和Database=abc会触发两个池
连接对象 Dispose() 不等于断开网络,只是归还给池
调用 conn.Close() 或 conn.Dispose() 后,物理 TCP 连接大概率没关闭,而是被放回池中等待复用。真正销毁连接要等池管理器判断超时(默认 4–8 分钟无活动)或池满主动清理。
这意味着:
- 频繁
new SqlConnection(...)+Close()是安全且推荐的,不用手动“复用 conn 实例” - 如果看到数据库端
sp_who2里连接数居高不下,不是泄露,很可能是池里积压着闲置连接 - 想强制清空当前应用的所有池,调用
SqlConnection.ClearAllPools();按连接字符串清空用SqlConnection.ClearPool(conn)
池大小和超时参数直接影响吞吐与错误类型
关键配置项: Max Pool Size(默认 100)、Min Pool Size(默认 0)、Connection Timeout(默认 15 秒)。它们不只影响性能,还决定报什么错。
典型现象与对策:
- 抛出
Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.—— 不是数据库慢,是池满了且没人释放,先检查是否有未Dispose()的连接,再看是否Max Pool Size设太小 - 冷启动延迟高(首次查询慢)—— 可设
Min Pool Size=5预热,但注意这会让空闲连接长期占着数据库资源 - 连接泄漏难定位——用
System.Data.SqlClient.SqlConnection.ConnectionString+ 日志埋点,或启用 ADO.NET ETW 事件跟踪Microsoft-AdoNet-SystemData
异步方法(如 OpenAsync)也走同一套池机制
await conn.OpenAsync() 和 conn.Open() 共享同一个连接池,底层没有“异步专用池”。区别只在调用线程是否阻塞,池内连接的获取、复用、超时逻辑完全一致。
要注意:
- 异步操作不会绕过池限制,
Max Pool Size同样生效 - 不要在
async void方法里开连接——异常可能丢失,连接无法保证被释放 - EF Core 的
DbContext默认每次SaveChangesAsync都会从池取新连接,不是复用上一次的DbConnection实例
SqlConnection 对象。










