我看到可怕的 "在从池中获取连接之前,超时时间已过 "错误。
我已经在代码中搜索了任何未关闭的db连接,但无法找到任何连接。
我想做的是:下次遇到这个错误时,让系统转储一个列表,列出哪些procs或http请求持有所有的句柄,这样我就可以找出是哪段代码造成的问题。
更好的办法是查看这些句柄被持有了多久,这样我就可以发现那些已经使用但未关闭的连接。
有什么方法可以做到这一点吗?
有一些很好的链接用于监控连接池。在谷歌上搜索".net连接池监控"。
我之前提到的一篇文章是 Bill Vaughn的文章 (请注意这是旧的,但仍然包含有用的信息)。它有一些关于监控连接池的信息,但一些伟大的见解,以及泄漏可能发生的地方。
对于监控,他建议
"监控连接池
好吧,所以你打开了一个连接并关闭了它,想知道连接是否还在原地--在气垫上的连接池里说着话。好吧,有几种方法可以确定有多少个连接还在原地(仍然连接着),甚至它们在做什么。我在这里和我的书中讨论了其中的几种方法。
- 使用SQL Profiler与SQLProfiler TSQL_Replay模板进行跟踪。对于那些熟悉Profiler的人来说,这比使用SP_WHO进行轮询要简单。
- 运行SP_WHO或SP_WHO2,它从sysprocesses表中返回所有工作进程的信息,显示每个进程的当前状态。一般来说,每个连接有一个SPID服务器进程。如果你给你的连接命名,使用连接字符串中的应用程序名称参数,就很容易找到。
- 使用性能监控器(PerfMon)来监控池和连接。我接下来会详细讨论这个问题。
- 在代码中监控性能计数器。这个选项允许你显示或简单地监控连接池的健康状况和建立的连接数。我将在本文后续章节中讨论这个问题。"
编辑。
和以往一样,查看一些 其他类似职位 在这里
第二次编辑。
一旦你确认连接没有被池子回收,你可以尝试的另一件事是利用StateChange事件来确认连接何时被打开和关闭。如果你发现打开的状态变化比关闭的状态变化多,那就说明在某些地方存在泄漏。如果你有其他的日志记录,你可以开始分析日志文件,看看是否有从关闭到打开的状态变化,而没有相应的打开到关闭。请看 这个环节 获取更多关于如何处理StateChangedEvent的信息。
如果你足够幸运,连接的创建和打开是集中的,那么下面的类应该可以很容易地发现泄漏的连接。享受 :)
using System.Threading; // not to be confused with System.Timer
/// <summary>
/// This class can help identify db connection leaks (connections that are not closed after use).
/// Usage:
/// connection = new SqlConnection(..);
/// connection.Open()
/// #if DEBUG
/// new ConnectionLeakWatcher(connection);
/// #endif
/// That's it. Don't store a reference to the watcher. It will make itself available for garbage collection
/// once it has fulfilled its purpose. Watch the visual studio debug output for details on potentially leaked connections.
/// Note that a connection could possibly just be taking its time and may eventually be closed properly despite being flagged by this class.
/// So take the output with a pinch of salt.
/// </summary>
public class ConnectionLeakWatcher : IDisposable
{
private readonly Timer _timer = null;
//Store reference to connection so we can unsubscribe from state change events
private SqlConnection _connection = null;
private static int _idCounter = 0;
private readonly int _connectionId = ++_idCounter;
public ConnectionLeakWatcher(SqlConnection connection)
{
_connection = connection;
StackTrace = Environment.StackTrace;
connection.StateChange += ConnectionOnStateChange;
System.Diagnostics.Debug.WriteLine("Connection opened " + _connectionId);
_timer = new Timer(x =>
{
//The timeout expired without the connection being closed. Write to debug output the stack trace of the connection creation to assist in pinpointing the problem
System.Diagnostics.Debug.WriteLine("Suspected connection leak with origin: {0}{1}{0}Connection id: {2}", Environment.NewLine, StackTrace, _connectionId);
//That's it - we're done. Clean up by calling Dispose.
Dispose();
}, null, 10000, Timeout.Infinite);
}
private void ConnectionOnStateChange(object sender, StateChangeEventArgs stateChangeEventArgs)
{
//Connection state changed. Was it closed?
if (stateChangeEventArgs.CurrentState == ConnectionState.Closed)
{
//The connection was closed within the timeout
System.Diagnostics.Debug.WriteLine("Connection closed " + _connectionId);
//That's it - we're done. Clean up by calling Dispose.
Dispose();
}
}
public string StackTrace { get; set; }
#region Dispose
private bool _isDisposed = false;
public void Dispose()
{
if (_isDisposed) return;
_timer.Dispose();
if (_connection != null)
{
_connection.StateChange -= ConnectionOnStateChange;
_connection = null;
}
_isDisposed = true;
}
~ConnectionLeakWatcher()
{
Dispose();
}
#endregion
}
我已经使用了这个
http:/www.simple-talk.comsqlperformancehow-to-identify-slow-running-queries-with-sql-profiler
为了找到之前长期运行的存储过程,我可以回溯并找到调用SP的方法。
不知道这是否有帮助