正确处理和关闭数据库对象的包装器

时间:2018-09-25 16:20:12

标签: asp.net vb.net sqldataadapter

我有一个简单的帮助程序功能,该功能可以在SQL Server数据库中查找数据并返回数据集。

此功能在我的Web应用程序中的许多不同地方都使用过。

在大多数情况下,它都很棒。但是,当有很多并发用户同时连接时,我偶尔会收到如下错误:

  

DBUtilities.getDataSet:建立与SQL Server的连接时发生与网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称正确,并且已将SQL Server配置为允许远程连接。

这种情况发生时,我在数据库服务器事件日志中看不到任何错误,仅在Web服务器事件日志中看到。

在阅读了有关垃圾收集和对象处置之后,我开始认为也许数据库连接没有被正确关闭或清除。

我想知道,是否有一种方法可以将这段代码放在某种类型的包装程序中,以帮助正确处理数据库对象?

这也是我指的功能:

Public Overloads Function getDataSet(ByVal commandText As String, Optional ByVal tableName As String = "") As DataSet

    Dim ds As New DataSet
    Dim conn As New SqlConnection(myConnStr)

    Try
        Dim cmd As New SqlCommand(commandText, conn)
        cmd.CommandTimeout = 30
        cmd.CommandType = CommandType.Text
        Dim da As New SqlDataAdapter
        da.SelectCommand = cmd
        conn.Open()

        If String.IsNullOrEmpty(tableName) Then
            da.Fill(ds)
        Else
            da.Fill(ds, tableName)
        End If
    Catch ex As Exception
        Throw New Exception("AppDataMethods.getDataSet: " & ex.Message & ", cmdText = " & commandText)
    Finally
        conn.Close()
        conn = Nothing
    End Try
    Return ds

End Function

1 个答案:

答案 0 :(得分:4)

Close()调用位于Finally块中,所以您可以。现代代码倾向于使用Using块,而conn = Nothing行在VB.Net中根本没有帮助(在VB6 / VBScript中是必需的,但没有更多),但是您应该拥有好的。如果您使用的是DataApater的conn.Open()方法,则也不需要调用Fill()

对我来说,最可怕的事情是要求commandText字符串,但无法接受单独的参数数据。这实际上迫使您在其他代码中构建严重不安全的SQL字符串,或者即使Overloads声明在其他地方也考虑使用它,仍然鼓励它作为处理SQL的默认方式。

我自己的数据方法往往总是要求传递SqlParameter数组,即使对于没有参数的查询(使用空数组),也要确保没有其他程序员可以使用我的数据库至少不了解查询参数。另外,有时我会使用功能性方法,而是使用委托/ lambda参数来分配参数。

我还倾向于在专用于数据库访问的新模块中将此方法构建为私有,然后在其中为每个现有查询创建公共方法。如果您有很多查询,在单独的类库项目中这也可能是Friend方法,因此您有几个类或模块可以将查询组织成逻辑组。

Private Overloads Function getDataSet(ByVal commandText As String, parameters As SqlParameter(), Optional ByVal tableName As String = "") As DataSet
    Dim result As New DataSet
    Using conn As New  SqlConnection(myConnStr), _
          cmd As New SqlCommand(commandText, conn), _
          da As New SqlDataAdapter(cmd)

        cmd.CommandTimeout = 30
        If parameters IsNot Nothing AndAlso parameters.Length > 0 Then
            cmd.Parameters.AddRange(parameters)
        End If

        If String.IsNullOrWhitespace(tableName) Then tableName = "Table1"
        da.Fill(result, tableName)

    End Using
    Return result    
End Function

我还删除了Catch块,因为它所做的唯一另一件事就是重新抛出了与您已有的异常类似的异常。您会丢失CommandText,但是如果您对每个查询都有专用的方法并使用参数化查询(如在其他地方所建议的那样),那么在CommandText中很少有很多信息不会直接从堆栈跟踪中获取。