2010-10-01 88 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