You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# MMO应用中SqlCommand超时及SQL连接泄漏问题求助

解决异步TCP Socket项目中SQL连接泄漏与超时问题

这问题我之前帮好几个开发者排查过,核心大概率是连接没有被正确释放回连接池,加上高负载下连接池耗尽,最终触发SqlCommand超时。咱们一步步拆解问题,找到根因和解决方案:

核心原因梳理

SQL Server默认开启连接池,正常调用SqlConnection.Close()或用using块释放连接时,连接会被放回池里复用,而非真正关闭物理连接。但你的连接计数持续增长,说明连接没被正确回收,导致连接池被占满——新请求拿不到可用连接,排队超过30秒就触发了超时。

常见排查方向&修复方案

1. 异步代码中using与await的误用

这是最常见的坑!异步场景下,如果没正确等待数据库操作完成,或者using块没包裹整个异步流程,会导致连接提前被释放或无法回收。

错误示例:

// 问题:没await异步操作,using块结束后连接被关闭,但存储过程还在执行
using(var conn = new SqlConnection(connectionString))
{
    conn.Open();
    var cmd = new SqlCommand("MyStoredProc", conn);
    cmd.ExecuteNonQueryAsync(); // 缺少await,连接提前被回收
}

正确写法:

using(var conn = new SqlConnection(connectionString))
{
    await conn.OpenAsync(); // 异步打开连接
    using(var cmd = new SqlCommand("MyStoredProc", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        // 添加存储过程参数...
        await cmd.ExecuteNonQueryAsync(); // 必须等待异步操作完成
    }
}

确保所有数据库相关的异步方法都加了await,且using块完整包裹从连接打开到命令执行结束的全流程。

2. 未处理的异常导致连接泄漏

如果数据库操作过程中抛出未捕获的异常,会不会影响连接回收?其实using块会自动调用Dispose(),把连接放回池,但如果是async void方法里的异常(比如TCP请求处理用了async void),异常会直接抛到线程池,可能导致后续流程异常,间接引发连接泄漏。

修复方案:

  • 避免在业务逻辑中使用async void,改用async Task;
  • 给数据库操作添加try-catch,记录异常并确保流程正常收尾:
try
{
    using(var conn = new SqlConnection(connectionString))
    {
        await conn.OpenAsync();
        using(var cmd = new SqlCommand("MyStoredProc", conn))
        {
            // 参数配置与执行逻辑
            await cmd.ExecuteReaderAsync();
        }
    }
}
catch(Exception ex)
{
    // 详细记录异常信息(包括请求ID、时间、存储过程名)
    Logger.Error($"请求[{requestId}]执行存储过程失败: {ex.Message}", ex);
    throw; // 重新抛出,让上层处理请求错误
}

3. 连接池配置或存储过程性能问题

  • 连接池上限不足:默认连接池最大连接数在.NET Framework是100,.NET Core+是100/核心。如果高负载请求数超过这个值,新请求会排队等待连接,超时触发。可以临时增大连接字符串的Max Pool Size(比如设为200),但这只是缓解,核心还是要解决连接泄漏:
    Server=YourServer;Database=YourDB;User Id=YourUser;Password=YourPwd;Max Pool Size=200;
    
  • 存储过程执行过慢:如果存储过程本身执行时间长,会导致连接被长时间占用,连接池可用连接越来越少。可以用SQL Server的sys.dm_exec_requests或Profiler跟踪存储过程的执行时间,排查是否有锁阻塞、慢查询等问题。

排查验证步骤

  1. 监控连接池状态:用Windows性能计数器查看SqlClient Connection Pool\Number of Active Connections,或者SQL Server的General Statistics\User Connections,确认活跃连接数是否持续增长;
  2. 测试连接回收:在测试环境中调用SqlConnection.ClearAllPools(),如果调用后连接计数骤降,说明确实是连接没被放回池;
  3. 检查长连接会话:用sp_who2或sys.dm_exec_sessions查看当前数据库会话,有没有长时间处于running或sleeping状态的会话,对应到你的应用进程。

内容的提问来源于stack exchange,提问作者Reza Akraminejad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:58:51