我是否泄漏了ADO.NET连接?

时间:2010-04-12 19:57:26

标签: sql-server vb.net winforms ado.net sql-server-2000

以下是我在DAL中的代码示例。对数据库的存储过程的所有调用都是以这种方式构建的,并且没有内联SQL。

Friend Shared Function Save(ByVal s As MyClass) As Boolean

    Dim cn As SqlClient.SqlConnection = Dal.Connections.MyAppConnection
    Dim cmd As New SqlClient.SqlCommand

    Try
        cmd.Connection = cn
        cmd.CommandType = CommandType.StoredProcedure
        cmd.CommandText = "proc_save_my_class"

        cmd.Parameters.AddWithValue("@param1", s.Foo)
        cmd.Parameters.AddWithValue("@param2", s.Bar)

        Return True

    Finally
        Dal.Utility.CleanupAdoObjects(cmd, cn)
    End Try

End Function

这是连接工厂(如果我使用正确的术语):

Friend Shared Function MyAppConnection() As SqlClient.SqlConnection

    Dim cn As New SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("MyConnectionString").ToString)
    cn.Open()

    If cn.State <> ConnectionState.Open Then
        ' CriticalException is a custom object inheriting from Exception.
        Throw New CriticalException("Could not connect to the database.")
    Else
        Return cn
    End If

End Function

这是Dal.Utility.CleaupAdoObjects()函数:

Friend Shared Sub CleanupAdoObjects(ByVal cmd As SqlCommand, ByVal cn As SqlConnection)
    If cmd IsNot Nothing Then cmd.Dispose()
    If cn IsNot Nothing AndAlso cn.State <> ConnectionState.Closed Then cn.Close()
End Sub

我收到了很多“超时已过期。在操作完成之前已经过了超时时间,或者服务器没有响应。”用户报告的错误消息。应用程序的DAL打开连接,读取或保存数据,然后关闭它。没有任何关系是开放的 - 故意!

托管SQL Server 2000的Windows 2000 Server上没有任何明显的迹象表明存在问题。事件日志中没有任何内容,SQL Server日志中没有任何内容。

超时是随机发生的 - 我无法重现。它发生在当天早些时候,系统中只有1到5个用户。它也发生在系统中大约50个用户。对于所有数据库,通过性能监视器与SQL Server的最多连接大约为74。

超时发生在代码中,这些代码既可以保存到应用程序的不同部分,也可以从应用程序的不同部分读取数据库。堆栈跟踪不指向一个或两个违规的DAL功能。它发生在许多不同的地方。

我的ADO.NET代码是否能够泄漏连接?我已经讨论了一下,我已经读过,如果连接池填满,就会发生这种情况。但是,我没有明确设置任何连接池。我甚至试图在连接字符串中增加连接超时,但是在300秒(5分钟)值之前很久就会发生超时:

<add name="MyConnectionString" connectionString="Data Source=MyServer;Initial Catalog=MyDatabase;Integrated Security=SSPI;Connection Timeout=300;"/>

我已经完全失去了导致这些Timeout问题的原因。任何想法都表示赞赏。

编辑:这是一个WinForms应用程序。

5 个答案:

答案 0 :(得分:3)

检查连接泄漏的一种方法是将max pool size添加到连接字符串,例如:

"integrated security=SSPI;server=MyHost;Max Pool Size=1;"

在开发中,我通常使用此设置运行(如果应用程序同时使用两个连接,则为2)。

答案 1 :(得分:2)

来自here

  

与Finalize不同,开发人员应明确调​​用Dispose以释放非托管资源。实际上,您应该在实现它的任何对象上显式调用Dispose方法,以释放对象可能持有引用的任何非托管资源。

SqlConnectionSqlCommandSqlDataReader等...全部实施IDisposable。如果将所有这些实例括在一个使用块中,则会自动调用Dispose,您的连接将被关闭,您不必担心这样的问题。启动反射器并自己查看:(SqlConnection.Dispose

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._userConnectionOptions = null;
        this._poolGroup = null;
        this.Close();
    }
    this.DisposeMe(disposing);
    base.Dispose(disposing);
}

这也使代码更短,因为您不必手动添加Finally块来清理ADO.NET对象。

Using connection As SqlConnection("your connection string")
    Using command As New SqlCommand("your sql", connection)
        connection.Open()
        Using dataReader As SqlDataReader = command.ExecuteReader()
            'Your stuff here
        End Using
    End Using
End Using

使用Using方法强制您将ADO.NET对象保持在本地,这对我来说是件好事。

答案 2 :(得分:1)

无论状态如何,您都应始终处置Connection:

 'If cn IsNot Nothing AndAlso cn.State <> ConnectionState.Closed Then cn.Close()
 If cn IsNot Nothing Then cn.Dispose()

我不确定这会导致你的超时,但肯定会有所改善。

答案 3 :(得分:0)

您的存储过程如何在应用程序之外执行?

如果您在Save()中将'return true'移出try / finally块怎么办?

监视perf监视器中的数据库连接,看它们是否会增长。

但我首先要看的是你自己的sprocs - 他们是否按照一致的顺序访问表格,或者你可能会遇到锁定?例如,如果proc1操作table1然后操作table2,而proc2命中table2然后table1,则可能会遇到锁定问题。

答案 4 :(得分:0)

这是一个Windows应用程序还是一个Web应用程序?

使用简单的存储过程或仅使用更复杂的存储过程是否会发生超时?

您是否尝试过运行sql profiler跟踪以查看是否有任何查询确实需要很长时间?

另外,您是否尝试过转换为“使用”语法,以确保对象被关闭并正确处理?