2010-10-01 54 views
4

我最近开始在我的开发机器上遇到SQL Server的数据库连接问题。如何解决连接池问题?

System.InvalidOperationException:Timeout过期。在从池中获取连接之前已经超时的时间段

如何监视连接池以找出发生了什么?

进一步信息:

我没有多少运气这个 - 我绝对不会泄漏连接。每个连接都在using声明中。

什么时候发生的问题,我有性能监视器窗口打开,它不是任何地方显示靠近泳池的限制(即100) - 一般在2 - 5连接,所以我不认为游泳池精疲力尽,所以也许是暂停。

但是,我已将ConnectionTimeout设置为0,根据文档,这意味着它应该永远等待连接 - 但我没有看到这一点。

当它发生时,它发生得相当快 - 我在VS2010的调试器下运行 - 启动我的应用程序的一个新实例 - 它可能发生在一两秒钟内 - 在启动应用程序有几个查询发生。我正在运行的实际SQL Server是SQL Express 2008.也许我应该尝试在SQL Server 2008上运行它,看看我是否看到任何不同的行为。

还有其他想法吗?

回答

3

看看有关池的ADO.NET Performance Counters

您描述的症状通常表明您正在泄漏连接。确保完成所有连接后,最好通过包装在using声明中。

+0

同意。很难最大限度地提高池 – gbn 2010-10-03 10:19:52

1

这里的一些代码来试试池,然后故障转移到UNPOOLED: 使用此子,如果有问题与池发生:

Public Sub OpenConn() 
    Dim sTempCNString As String = cn.ConnectionString 

    Try 
     ' add a timeout to the cn string, following http://www.15seconds.com/issue/040830.htm 
     Dim iTimeOut As Integer = utils_Configuration.Get_ConfigInt("DBConnectTimeout", 0) 
     If (iTimeOut > 0 And Not cn.ConnectionString.ToLower.Contains("timeout")) Then 
      Diagnostics.Debug.Print("<><><><><><><> SHORT CONNECT WITH POOLING <><><><><><><><><> ") 
      cn.ConnectionString += ";Connect Timeout=" & iTimeOut.ToString() & ";" 
     End If 

     cn.Open() 
     IsOperational = True 
    Catch ex As Exception 
     Diagnostics.Debug.Print("ERROR IN OPENING, try no pool") 
     ' see http://www.15seconds.com/issue/040830.htm 
     ' turn off pooling 
     Diagnostics.Debug.Print("<><><><><><><> CONNECT WITHOUT POOLING <><><><><><><><><> ") 
     Dim sAddOn As String = ";Pooling=false;Connect Timeout=45;" 
     cn.ConnectionString = sTempCNString & sAddOn 
     cn.ConnectionString = cn.ConnectionString.Replace(";;", ";") 
     cn.Open() 
    End Try 
End Sub 

下面是一些代码来监视池:

Option Explicit On 
Option Strict On 

Imports System.Data.SqlClient 
Imports System.Diagnostics 
Imports System.Runtime.InteropServices 
Imports Microsoft.VisualBasic 


' ref: http://msdn2.microsoft.com/en-us/library/ms254503.aspx 

Public Class utils_SqlPerfMon 

    Private PerfCounters(9) As PerformanceCounter 
    Private connection As SqlConnection 
    Public sConnectString As String = "" 
    Public sResult As String = "" 

    Public Sub New() 
     sConnectString = Tools.GetMainDBConn().ConnectionString 
     connection = New SqlConnection(sConnectString) 
     Exec() 
    End Sub 

    Public Sub New(ByVal strC As String) 
     sConnectString = strC 
     connection = New SqlConnection(sConnectString) 
     Exec() 
    End Sub 

    Public Sub Exec() 

     Me.SetUpPerformanceCounters() 
     Diagnostics.Debug.Print("Available Performance Counters:") 

     ' Create the connections and display the results. 
     Me.CreateConnectionsAndDisplayResults() 

    End Sub 

    Private Sub CreateConnectionsAndDisplayResults() 
     ' List the Performance counters. 
     WritePerformanceCounters() 

     Dim connection1 As SqlConnection = New SqlConnection(_ 
      Me.sConnectString) 
     connection1.Open() 

     Diagnostics.Debug.Print("Opened the 1st Connection:") 
     WritePerformanceCounters() 

     connection1.Close() 
     Diagnostics.Debug.Print("Closed the 1st Connection:") 
     WritePerformanceCounters() 


     Return 


    End Sub 

    Private Enum ADO_Net_Performance_Counters 
     NumberOfActiveConnectionPools 
     NumberOfReclaimedConnections 
     HardConnectsPerSecond 
     HardDisconnectsPerSecond 
     NumberOfActiveConnectionPoolGroups 
     NumberOfInactiveConnectionPoolGroups 
     NumberOfInactiveConnectionPools 
     NumberOfNonPooledConnections 
     NumberOfPooledConnections 
     NumberOfStasisConnections 
     ' The following performance counters are more expensive to track. 
     ' Enable ConnectionPoolPerformanceCounterDetail in your config file. 
     '  SoftConnectsPerSecond 
     '  SoftDisconnectsPerSecond 
     '  NumberOfActiveConnections 
     '  NumberOfFreeConnections 
    End Enum 

    Private Sub SetUpPerformanceCounters() 
     connection.Close() 
     Me.PerfCounters(9) = New PerformanceCounter() 

     Dim instanceName As String = GetInstanceName() 
     Dim apc As Type = GetType(ADO_Net_Performance_Counters) 
     Dim i As Integer = 0 
     Dim s As String = "" 
     For Each s In [Enum].GetNames(apc) 
      Me.PerfCounters(i) = New PerformanceCounter() 
      Me.PerfCounters(i).CategoryName = ".NET Data Provider for SqlServer" 
      Me.PerfCounters(i).CounterName = s 
      Me.PerfCounters(i).InstanceName = instanceName 
      i = (i + 1) 
     Next 
    End Sub 

    Private Declare Function GetCurrentProcessId Lib "kernel32.dll"() As Integer 

    Private Function GetInstanceName() As String 
     'This works for Winforms apps. 
     'Dim instanceName As String = _ 
     ' System.Reflection.Assembly.GetEntryAssembly.GetName.Name 

     ' Must replace special characters like (,), #, /, \\ 
     Dim instanceName As String = _ 
      AppDomain.CurrentDomain.FriendlyName.ToString.Replace("(", "[") _ 
      .Replace(")", "]").Replace("#", "_").Replace("/", "_").Replace("\\", "_") 

     'For ASP.NET applications your instanceName will be your CurrentDomain's 
     'FriendlyName. Replace the line above that sets the instanceName with this: 
     'instanceName = AppDomain.CurrentDomain.FriendlyName.ToString.Replace("(", "[") _ 
     ' .Replace(")", "]").Replace("#", "_").Replace("/", "_").Replace("\\", "_") 

     Dim pid As String = GetCurrentProcessId.ToString 
     instanceName = (instanceName + ("[" & (pid & "]"))) 
     Diagnostics.Debug.Print("Instance Name: {0}", instanceName) 
     Diagnostics.Debug.Print("---------------------------") 
     Return instanceName 
    End Function 

    Private Sub WritePerformanceCounters() 
     Dim sdelim As String = vbCrLf ' "<br>" 
     Diagnostics.Debug.Print("---------------------------") 
     sResult += "---------------------------" 
     sResult += sdelim 

     Dim strTemp As String = "" 
     For Each p As PerformanceCounter In Me.PerfCounters 
      Try 
       Diagnostics.Debug.Print("{0} = {1}", p.CounterName, p.NextValue) 
       strTemp = p.CounterName & "=" & p.NextValue.ToString 
      Catch ex As Exception 
       strTemp = "" 
      End Try 
      sResult += strTemp 
      sResult += sdelim 
     Next 
     Diagnostics.Debug.Print("---------------------------") 
     sResult += "---------------------------" 
      sResult += sdelim 
    End Sub 


    Private Shared Function GetSqlConnectionStringDifferent() As String 
     ' To avoid storing the connection string in your code, 
     ' you can retrive it from a configuration file. 
     Return ("Initial Catalog=AdventureWorks;Data Source=.\SqlExpress;" & _ 
      "User Id=LowPriv;Password=Data!05;") 
    End Function 


End Class