目前所有连接都收到“超时过期”

use*_*567 4 sql-server ado.net

我有一个连接到 SQL Server 的应用程序。目前我得到,

Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.
Run Code Online (Sandbox Code Playgroud)

我跑的时候,

SELECT 
    DB_NAME(dbid) as DBName, 
    COUNT(dbid) as NumberOfConnections,
    loginame as LoginName
FROM
    sys.sysprocesses
WHERE 
     DB_NAME(dbid) ='MyDb'
GROUP BY 
    dbid, loginame 

DBName  NumberOfConnections LoginName
MyDb    10                     sa                                                                                                                              
MyDb    109                   MyUser
Run Code Online (Sandbox Code Playgroud)

所有进程的状态是sleeping,cms是AWAITING COMMAND

这是我的代码,

private async Task<object> ExecuteAsync<T>(ExecutionType executionType, CommandType commandType, string commandText, IsolationLevel isolationLevel, SqlParameter[] parameters, Func<IDataReader, T> callback = null)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    using (var connection = new SqlConnection(_settings.DatabaseConnectionString))
    {
        using (var command = new SqlCommand(commandText, connection) {CommandType = commandType})
        {
            command.Parameters.AddRange(parameters);
            await connection.OpenAsync().ConfigureAwait(false);
            command.CommandTimeout = _settings.CommandTimeout;
            var transaction = connection.BeginTransaction(isolationLevel);
            command.Transaction = transaction;
            try
            {
                object result;
                switch (executionType)
                {
                    case ExecutionType.Reader:
                        var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);
                        using (reader)
                        {
                            var list = new List<T>();
                            while (reader.Read())
                            {
                                if (callback != null)
                                {
                                    var item = callback(reader);
                                    if (item != null)
                                    {
                                        list.Add(item);
                                    }
                                }
                            }
                            result = list;
                        }
                        break;
                    case ExecutionType.NonQuery:
                        result = await command.ExecuteNonQueryAsync().ConfigureAwait(false);
                        break;
                    default:
                        result = await command.ExecuteScalarAsync().ConfigureAwait(false);
                        break;
                }
                transaction.Commit();
                stopwatch.Stop();
                var elapsed = stopwatch.Elapsed;
                if (elapsed.Seconds > 2)
                {
                    _logger.Log(string.Format("{0} took {1} time", command.CommandText, elapsed));// only log if it tooks more than 2 seconds
                }
                return result;
            }
            catch (Exception exception)
            {
                _logger.Log(exception);
                transaction.Rollback();
                throw;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Tho*_*ger 8

看起来您的应用程序没有正确关闭或处理SqlConnection对象。默认情况下,SqlConnection最大池大小为 100

此处的解决方法是使用应用程序找出连接未被清理的原因,因为它们在特定连接池中仍处于“活动状态”,这就是您无法获取另一个连接的原因,因为没有要使用的池中的非活动连接。

应用程序应该调用SqlConnection.Close()SqlConnection.Dispose()以释放连接并将其标记为“非活动”。

我写了一篇关于连接池广泛的博客文章(SQL Server DBA 的连接池),它应该阐明为什么你会看到你所看到的,以及对这个问题的编程修复。


And*_*ton 5

另一种方法是,如果您正在处理大量记录,您实际上可能会遇到误导性错误。可能是您已经用完了 PC 上的所有端口,您可以通过运行 Sysinternals TCPView来检查这一点。

如果您看到数以千计的TIME_WAIT,这可能是一个原因。

本质上,在您的应用程序关闭与数据库的连接后(在 结束时using (var connection = new SqlConnection(_settings.DatabaseConnectionString))),TCP 将等待近 4 分钟,然后正在使用的端口可以再次免费使用。

从内存中,您需要在 4 分钟内处理大约 16,000 次执行才能发生这种情况(这将取决于您的操作系统版本以及您在该 PC 上运行的其他内容)。