在大多数情况下,连接池问题与“连接泄漏”有关。您的应用程序可能无法正确且一致地关闭其数据库连接。当您保持连接打开状态时,它们将保持阻塞状态,直到.NET垃圾收集器通过调用它们的Finalize()
方法为您关闭它们为止。
您要确保确实关闭了连接。例如,下面的代码将导致一个连接泄漏,如果之间的代码.Open
和Close
抛出异常:
var connection = new SqlConnection(connectionString);
connection.Open();
// some code
connection.Close();
正确的方法是这样的:
var connection = new SqlConnection(ConnectionString);
try
{
connection.Open();
someCall (connection);
}
finally
{
connection.Close();
}
要么
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
someCall(connection);
}
当函数从类方法返回连接时,请确保在本地缓存该连接并调用其Close
方法。您将使用以下代码泄漏连接,例如:
var command = new OleDbCommand(someUpdateQuery, getConnection());
result = command.ExecuteNonQuery();
connection().Close();
从第一个调用返回的连接getConnection()
未关闭。此行不是关闭您的连接,而是创建一个新的并尝试关闭它。
如果您使用SqlDataReader
或OleDbDataReader
,请关闭它们。尽管关闭连接本身似乎可以解决问题,但是在使用数据读取器对象时,要付出额外的努力来明确关闭它们。
MSDN / SQL Magazine上的文章“ 为什么连接池会溢出? ”解释了很多细节并提出了一些调试策略:
- 运行
sp_who
或sp_who2
。这些系统存储过程从sysprocesses
系统表返回信息,该表显示所有工作进程的状态和信息。通常,每个连接都会看到一个服务器进程ID(SPID)。如果使用连接字符串中的“应用程序名称”自变量命名连接,则可以轻松找到工作连接。
- 结合使用SQL Server Profiler和SQLProfiler
TSQL_Replay
模板来跟踪打开的连接。如果您熟悉Profiler,则此方法比使用sp_who轮询更容易。
- 使用性能监视器来监视池和连接。我稍后讨论这种方法。
- 监视代码中的性能计数器。您可以使用例程提取计数器或使用新的.NET PerformanceCounter控件来监视连接池的运行状况和已建立的连接数。