Дизайн оболочки базы данных C # - PullRequest
3 голосов
/ 24 августа 2010

Я разрабатываю оболочку базы данных для C #. Ниже приведены два варианта, которые у меня есть:

Вариант А:

class DBWrapper:IDisposable
{
     private SqlConnection sqlConn;

     public DBWrapper()
     {
            sqlConn = new SqlConnection("my connection string");
            sqlConn.Open();
     }

     public DataTable RunQuery(string Sql)
     {
              implementation......
     }

     public Dispose()
     {
            if(sqlConn != null)
                   sqlConn.Close();
     }
}

Вариант B:

class DBWrapper
{
     public DBWrapper()
     {            
     }

     public DataTable RunQuery(string Sql)
     {
             SqlConnection sqlConn = new SqlConnection("my connection string");
             .....implementation......
             sqlConn.Close();               
     }   
}

Для опции A соединение открывается, когда создается экземпляр класса. Поэтому независимо от того, сколько раз вызывающая сторона вызывает RunQuery, соединение всегда готово. Но если приложение создает экземпляр DBWrapper в начале приложения, соединение будет просто открыто и ничего не будет делать, пока приложение не будет завершено. Кроме того, он может иметь много экземпляров DBWrapper во время выполнения. Итак, это своего рода тратить ресурсы.

Для опции B у нее нет проблем, как у опции A, но новое соединение должно открываться и закрываться каждый раз, когда вызывающая сторона вызывает RunQuery. Я не уверен, насколько это повредит производительности.

Пожалуйста, поделитесь своим опытом. Спасибо за чтение.

Ответы [ 5 ]

6 голосов
/ 24 августа 2010

По соображениям производительности вы определенно не захотите использовать вариант B (по крайней мере, в тех случаях, которые я испытывал). Позвольте мне предложить вариант C:

class DBWrapper:IDisposable { private SqlConnection sqlConn;

public void EnsureConnectionIsOpen()
{
    if (sqlConn == null)
    {
      sqlConn = new SqlConnection("my connection string");
      sqlConn.Open();
    }

}

public DataTable RunQuery(string Sql)
{
    EnsureConnectionIsOpen();
    implementation......
}

public Dispose()
{
   if(sqlConn != null)
              sqlConn.Close();
}

} 

Вы можете рассмотреть возможность использования шаблона синглтона, чтобы убедиться, что существует только один экземпляр вашего DBWrapper.

2 голосов
/ 24 августа 2010

Сборщик мусора запускается в довольно сложных условиях, но в основном он вызывается, когда память превышает некоторый предел, он также вызывается периодически, но период не является постоянным. Вы никогда не можете быть уверены, когда именно сборщик мусора удаляет и, следовательно, (при другом запуске) уничтожает объект. Вы можете быть уверены в том, что сборщик мусора никогда не удалит и не уничтожит объект, на который все еще есть ссылки. Например, объект, на который ссылаются статические переменные в классе, не будет ни уничтожен, ни уничтожен.

2 голосов
/ 24 августа 2010

Несколько комментариев, заслуживающих рассмотрения:

В подходе, где вы управляете (возможно) долгоживущим соединением, важно проверить, открыто ли соединение, прежде чем выполнять запрос. Ранее я сталкивался с проблемами, когда через некоторое время NETCF закрывал неиспользуемые соединения.

В подходе, где вы открываете новое соединение для каждого запроса, убедитесь, что все ваше соединение, команды и (если они используются) средства чтения данных правильно упакованы в операторы или блоки try / finally + dispose () для освобождения соединений и замки.

Удачного кодирования!

1 голос
/ 24 августа 2010

Вариант B более транзакционный, что имеет свои преимущества.ADO.NET использует неявный пул соединений, поэтому вам не нужно часто беспокоиться о создании новых экземпляров SqlConnection.

Вам следует подумать, используете ли вы подключенную или отключенную модель данных;поскольку второй подход лучше подходит для автономной модели.

Но, как я уже сказал выше, пул соединений означает, что он практически не имеет значения в практическом плане.

0 голосов
/ 24 августа 2010

У вас может быть опция C, где база данных открывается по запросу в RunQuery (если она не открыта) и закрывается при удалении (когда она была открыта). Таким образом, база данных открывается только тогда, когда она действительно необходима, и открывается только один раз.

Так в псевдокоде:

class DBWrapper
{

     public DBWrapper()
     {            
     }

     SqlConnection sqlConn = null; 

     public DataTable RunQuery(string Sql)
     {
             if(sqlConn == null) sqlConn = new SqlConnection("my connection string");
             .....implementation......               
     }   
     public Dispose()
     {
            if(sqlConn != null)
                   sqlConn.Close();
     }

}

Также помните, что момент вызова Dispose не всегда непосредственно после того, как объект больше не нужен (например, переменная функции после использования функции). Насколько я знаю, это будет выполнено, когда сборщик мусора собирает объект (который не напрямую). Но я не совсем уверен в этом. Это поведение может также отличаться в веб-приложениях и приложениях без веб-приложений.

...