如何解决连接池问题?

发布于 2024-09-25 19:21:54 字数 636 浏览 2 评论 0原文

我最近开始在我的开发计算机上遇到 SQL Server 的数据库连接问题。

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

如何监视连接池以了解发生了什么情况?

更多信息:

我在这方面运气不太好 - 我绝对没有泄漏连接。每个连接都位于 using 语句内。

当问题确实发生时,我打开了性能监视器窗口,并且它没有显示任何接近池限制(即 100)的地方 - 通常大约有 2 - 5 个连接,所以我认为池没有耗尽,所以也许这是一个超时。

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

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

还有其他想法吗?

I have recently started encountering Database connection issues with SQL Server on my development machine.

System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool

How can I monitor the connection pool to figure out what is happening?

Further Info:

I haven't had much luck with this - I'm definitely not leaking connections. Every connection is inside a using statement.

When the problem does occur, I have the Performance Monitor window open and it's not showing anywhere near the limit of the pool (which is 100) - generally around 2 - 5 connections, so I don't think the pool is being exhausted so maybe it's a timeout.

However, I have set the ConnectionTimeout to 0 - which, according to the documentation, means it should wait forever to connect - but I'm not seeing this.

When it does occur, it happens fairly quickly - I'm running under the debugger from VS2010 - starting a new instance of my application - and it might happen within a second or two of starting - in starting up the app there are several queries that happen. The actual SQL Server I'm running against is SQL Express 2008. Maybe I should try running it against SQL Server 2008 and see if I see any different behaviour.

Any other ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

九厘米的零° 2024-10-02 19:21:54

查看与池相关的 ADO.NET 性能计数器

您所描述的症状通常表明您存在泄漏连接。确保所有连接在完成后都已释放,最好通过使用 using 语句进行包装。

Take a look at the ADO.NET Performance Counters related to pooling.

Your described symptom is often an indication that you are leaking connections. Make sure all connections are disposed when you are finished with them, preferably by wrapping in an using statement.

决绝 2024-10-02 19:21:54

下面是一些尝试池然后故障转移到非池化的代码:
如果池出现问题,请使用此子程序:

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

here's some code to try the pool and then failover to unpooled:
use this sub if a problem happens with the pool:

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

Here's some code to monitor the pool:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文