代码之家  ›  专栏  ›  技术社区  ›  SkyeBoniwell

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

  •  2
  • SkyeBoniwell  · 技术社区  · 6 年前

    这个函数在我的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 回复  |  直到 6 年前
        1
  •  4
  •   Joel Coehoorn    6 年前

    这个 Close() 电话在电话亭里 Finally 布洛克,你没事。现代代码倾向于 Using conn = Nothing 行在VB.Net中一点帮助都没有(在VB6/VBScript中需要它,但已经没有了),但是您所拥有的应该是可以的。你也不需要打电话 conn.Open() Fill() 方法。

    这个 最可怕的 对我来说就是要求 commandText 字符串,无法接受单独的参数数据。这实际上迫使您在其他代码中构建非常不安全的SQL字符串,或者仍然鼓励将其作为处理SQL的默认方法,即使 Overloads

    我自己的数据方法倾向于 需要通过 SqlParameter

    我也倾向于将此方法构建为 ,然后在其中为每个现有查询公开方法。如果您有许多查询,这也可能是一个 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中很少有您无法直接从堆栈跟踪中获得的信息。