ADO.NET SqlConnection连接池默认启用(Pooling=true),由SqlClient自动管理;只需标准连接字符串且不设Pooling=false即生效,Open/Close控制复用,字符串完全一致才属同一池。

连接字符串里加 Pooling=true 就启用了,但默认就是开的
ADO.NET 的 SqlConnection 连接池不是要手动创建或初始化的对象,而是由 SqlClient 库在底层自动管理的。只要用标准的 SqlConnection 构造函数传入含服务器、数据库名等信息的连接字符串,且没显式关掉池化,连接池就已生效。
常见误区是以为要写代码“开启池化”——其实只要不写 Pooling=false,它就在运行。验证是否启用:查连接字符串解析后的 ConnectionStringBuilder.Pooling 属性,或看 SQL Server 的 sys.dm_exec_sessions 中相同登录名+数据库的会话复用情况。
-
Pooling=true是默认值,可省略;显式写出更清晰 - 连接字符串完全一致(包括空格、大小写、分号位置)才视为同一池;
Database=MyDB和Initial Catalog=MyDB虽语义等价,但字符串不同 → 分属两个池 - Windows 身份验证下,不同 Windows 用户账号即使连同一库,也分属不同池(凭据不同)
Open() 和 Close() 才是池化关键动作,不是 Dispose()
调用 connection.Open() 时,SqlClient 会先查是否有可用空闲连接;有则复用,无则新建并加入池。调用 connection.Close() 时,连接不会真正断开,而是归还给池等待下次复用。而 Dispose() 只是确保 Close() 被执行(如果还没调),它本身不触发池操作。
- 必须配对使用
Open()/Close()或用using块(隐式调Dispose()→Close()) - 只
New SqlConnection(...)不Open(),不会占用池资源 - 忘了
Close()或异常跳出作用域又没using,连接会一直占用池中 slot,直到超时被回收(默认 4–8 分钟),拖慢后续请求
调整 Max Pool Size 和 Min Pool Size 要看实际负载,别盲目设高
连接池大小不是越大越好。SQL Server 单实例能支撑的并发连接数有限(受内存、线程、许可证限制),过大的 Max Pool Size 会导致连接堆积、超时,甚至触发 SQL Server 的连接拒绝(错误 10928 或 10929)。
-
Max Pool Size=100是默认值;中小型 Web API 通常 50–80 足够,高并发服务可试 150,但需配合 SQL Server 的max degree of parallelism和内存配置 -
Min Pool Size=0是默认值;设为非零(如5)能让池预热,但闲置连接仍占资源,IIS 应用池回收后这些连接就失效了,反而增加首次请求延迟 - 连接池超时由
Connection Timeout控制(默认 15 秒),和池内连接的空闲超时(Connection Lifetime)无关;后者用于强制轮换连接(如负载均衡场景),一般不用设
连接池失效的典型场景:连接字符串动态拼接、证书/Token 变更、防火墙重置
池化依赖连接字符串字面量完全一致 + 后端服务状态稳定。一旦以下情况发生,新连接无法复用旧池,会创建新池甚至导致池泄漏:
- 用
string.Format或$"..."拼接连接字符串,每次生成的字符串对象内容微异(比如时间戳、随机数、环境变量值)→ 每次都建新池 - 使用 Azure SQL 的
AccessToken认证时,Token 过期后新连接带新 Token → 字符串变化 → 新池;应改用SqlAuthenticationMethod.ActiveDirectoryInteractive或托管身份 - 网络中间件(如某些云防火墙、代理)主动断开空闲连接,但池 unaware,仍认为连接可用 → 后续
Open()报错Timeout expired或A transport-level error
这类问题不会立刻暴露,往往在压测或流量突增时集中爆发,排查时重点抓连接字符串生成逻辑和网络稳定性。



















