Оболочка, которая правильно удаляет и закрывает объекты базы данных - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть простая вспомогательная функция, которая ищет данные в базе данных SQL Server и возвращает набор данных.

Эта функция используется в разных местах моего веб-приложения.

Дляпо большей части, это прекрасно работает.Однако, когда одновременно подключено большое количество одновременно подключенных пользователей, я иногда получаю сообщения об ошибках, подобных этому:

DBUtilities.getDataSet: при установлении ошибки, связанной с сетью или экземпляром, произошла ошибка.подключение к SQL Server.Сервер не найден или не был доступен.Убедитесь, что имя экземпляра указано правильно и что SQL Server настроен для разрешения удаленных подключений.

Когда это происходит, я не вижу никаких ошибок в журнале событий сервера базы данных, только событие веб-сервераlogs.

После прочтения о сборке мусора и утилизации объектов я начинаю думать, что, возможно, соединения с базой данных не закрываются или не удаляются должным образом.

Мне было интересно, не будет либыть способом поместить этот код в какую-нибудь оболочку, которая может помочь правильно утилизировать объекты базы данных?

Вот функция, о которой я тоже говорю:

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 голосов
/ 25 сентября 2018

Вызов Close() находится в блоке Finally, так что все в порядке.Современный код предпочитает вместо этого блоки Using, а строка conn = Nothing вообще не помогает в VB.Net (это было необходимо в VB6 / VBScript, но не более), но то, что у вас должно быть, должно быть в порядке.Вам также не нужно вызывать conn.Open(), если вы используете метод Fill() DataApater.

Мне кажется, что самый страшный запрашивает строку commandText без возможности принимать отдельные данные параметров.Это практически вынуждает вас создавать небезопасные строки SQL в другом коде или по-прежнему поощряет его как способ обработки SQL по умолчанию, даже если объявление Overloads объясняет это в другом месте.

Мои собственные методы данных, как правило, всегда требуют передачи массива SqlParameter, даже для запросов без параметров (используйте пустой массив), чтобы другие программисты не могли использовать мою базу данныхне имея хотя бы некоторой осведомленности о параметрах запроса.В качестве альтернативы я иногда использую функциональный подход и вместо этого имею аргумент делегата / лямбды для назначения параметров.

Я бы также хотел построить этот метод как Private , в новом модуле, предназначенном длядоступ к базе данных, а затем обнародовать методы для каждого из ваших существующих запросов.Если у вас много запросов, это также может быть метод 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, которую вы не получили бы непосредственно из трассировки стека.

...