连接池不是自动开启的,得显式启用
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实例 池行为高度依赖字符串一致性与及时释放,最常出问题的地方不在“怎么配”,而在“以为配对了”和“以为已释放”。调试时优先抓运行时实际连接字符串和 GC 后是否真没了
SqlConnection对象。
