Класс Connection

60

Платформа .NET Framework включает собственную технологию доступа к данным — ADO.NET. Эта технология состоит из управляемых классов, позволяющих приложениям .NET подключаться к источникам данных (обычно реляционным базам данных), выполнять команды и управлять автономными данными. Маленькое чудо ADO.NET заключается в том, что эта технология позволяет писать более-менее одинаковый код для доступа к данным — как в веб-приложениях, так и в клиент-серверных настольных приложениях, и даже в однопользовательских приложениях, подключаемых к локальной базе данных.

Узнать все основы работы с ADO.NET в контексте клиентских приложений вы можете в разделе ADO.NET. Я не буду здесь описывать что такое поставщики данных и что из себя представляет архитектура ADO.NET, вы должны иметь общее представление о классах подключенного уровня - Connection, Command, DataReader, DataAdapter и о классах автономного уровня DataSet, DataTable, DataRow и т.п. Далее я буду рассматривать архитектуру ADO.NET в контексте веб-приложений ASP.NET. В качестве поставщика данных я буду использовать System.Data.SqlClient (SQL Server).

Класс Connection позволяет устанавливать соединения с источником данных, с которым нужно взаимодействовать. Перед тем, как можно будет делать что-то еще (в том числе извлечение, удаление, вставка или обновление данных), понадобится установить соединение. Ключевые свойства и методы Connection определены интерфейсом IDbConnection, который реализуют все классы Connection.

Строки соединений

При создании объекта Connection понадобится предоставить строку соединения. Строка соединения представляет собой последовательность пар "имя-значение", разделенных точками с запятой (;). Порядок этих настроек, как и регистр, не важен. Все вместе они указывают базовую информацию, необходимую для установки соединения.

Хотя строки соединений варьируются в зависимости от реляционной СУБД и используемого поставщика данных, несколько фрагментов информации необходимы почти всегда; эти фрагменты описаны ниже:

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

string connectionString = 
    @"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True";

Если интегрированная безопасность не поддерживается, при подключении должны быть указаны корректные имя и пароль пользователя. Во вновь установленной базе данных SQL Server обычно присутствует учетная запись sa ("system administrator" — системный администратор). Вот строка соединения, использующая эту учетную запись:

string connectionString =
    @"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;" +
    "user id=sa;password=opensesame";

Если вы пользуетесь поставщиком OLE DB, то строка соединения будет похожа на предыдущую, но добавятся дополнительный параметр настройки, идентифицирующий драйвер OLE DB (Provider=MSDAORA), а для подключения к файлу базы данных Access понадобиться указать «Provider=Microsoft.Jet.OLEDB.4.0».

Если вы используете базу данных, отличную от SQL Server, то может возникнуть необходимость проконсультироваться с документацией поставщика данных (или справочником по библиотеке классов .NET Framework), чтобы узнать о поддерживаемых значениях строки соединения. Например, большинство баз данных поддерживают настройку тайм-аута соединения, устанавливающую время ожидания соединения в секундах до того, как должно быть сгенерировано исключение. (Для SQL Server по умолчанию принято 15 секунд.)

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

Нет причин жестко кодировать строку соединения. В файле web.config есть раздел <connectionString> — самое подходящее место для сохранения строки соединения. Ниже показан пример:

<configuration>
  ...

  <connectionStrings>
    <add name="Northwind" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"/>
  </connectionStrings>
</configuration>

Затем эту строку соединения легко извлечь по имени из коллекции WebConfigurationManager.ConnectionStrings. При условии, что импортировано пространство имен System.Web.Configuration, для этого можно воспользоваться следующим оператором:

string stringConnection = 
    WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

В приведенных ниже примерах предполагается, что эта строка соединения добавлена в файл web.config.

Тестирование соединения

После выбора строки соединения управлять подключением очень легко — нужно просто использовать методы Open() и Close(). Более того, интерфейс IDbConnection унаследован от интерфейса IDisposable, который определяет реализующий его класс как ресурс. Поэтому при использовании класса Connection можно применять конструкцию using, не вызывая метод Close() - как только компилятор достигнет конца этой конструкции, соединение само закроется.

Приведенный ниже код в обработчике события Page.Load можно использовать для проверки соединения и вывода его состояния в текст метки. Чтобы код работал, понадобится импортировать пространство имен System.Data.SqlClient:

protected void Page_Load(object sender, EventArgs e)
{
        // Создать объект Connection
        string connectionString = 
            WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

        SqlConnection connection = new SqlConnection(connectionString);
        
        using (connection)
        {
            // Открыть соединение
            connection.Open();

            Label1.Text = "<b>Версия сервера: </b>" + connection.ServerVersion;
            Label1.Text += "<br /><b>Состояние соединения: </b> " + connection.State.ToString();
        }

        Label1.Text += "<br /><b>Состояние соединения после using: </b> " + connection.State.ToString();

}
Создание подключения к базе данных SQL Server

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

Организация пула соединений

Получение соединения требует небольшого, но заметного времени. В веб-приложении, в котором эффективно обрабатываются запросы, соединения будут открываться и закрываться бесконечно — по мере обработки новых запросов. В этой среде небольшие накладные расходы на установку соединения становятся весьма ощутимыми, и ограничивают масштабируемость системы.

Одним из решений проблемы может быть организация пула соединений. Пул соединений — это практика хранения постоянного набора открытых подключений к базе данных, разделяемых между сеансами, которые используют один и тот же источник данных. Это позволяет избежать необходимости в постоянном создании и уничтожении соединений. Пулы соединений в ADO.NET полностью прозрачны для программиста, и код доступа к данным не потребует никаких изменений. Когда клиент запрашивает соединение, вызывая Open(), соединение обслуживается непосредственно из доступного пула, без повторного создания. Когда клиент освобождает соединение вызовом Close() или Dispose() (IDisposable), оно не закрывается, а возвращается в пул, чтобы обслуживать следующий запрос.

ADO.NET не содержит механизма организации пула соединений. Однако большинство поставщиков данных ADO.NET реализуют некоторую форму такого пула. Поставщики данных SQL Server и Oracle предлагают собственные эффективные алгоритмы организации пулов соединений. Эти алгоритмы реализованы полностью в управляемом коде и, в противовес распространенным заблуждениям, не используют службы уровня предприятия COM+. Чтобы соединение было повторно использовано в SQL Server или Oracle, строки подключений должны в точности совпадать. Если они отличаются хоть немного, создается новое подключение в новом пуле.

Пулы соединений SQL Server и Oracle используют механизм полнотекстового сравнения. Это значит, что любое минимальное изменение в строке соединения нарушает пул, даже если в ней просто изменяется порядок параметров или добавляется дополнительный пробел в конце. По этой причине важно не кодировать жестко строки соединений на различных веб-страницах. Вместо этого необходимо сохранять строку соединения в одном месте — предпочтительно в разделе <connectionString> файла web.config.

В обоих поставщиках данных — SQL Server и Oracle — пулы соединений включаются и используются автоматически. Однако можно также использовать параметры строки соединения для настройки размеров пула. Эти параметры описаны в таблице ниже:

Параметры для настройки пула соединений
Параметр Описание
Max Pool Size

Максимальное количество соединений, разрешенных в пуле (по умолчанию 100). Если достигается максимальный размер пула, любые последующие попытки открыть соединение помещаются в очередь в ожидании освобождений соединения. (Если время длительностью Connection.Timeout истекает перед тем, как освободится такое соединение, возникает ошибка.)

Min Pool Size

Минимальное количество соединений, которые должны оставаться в пуле (по умолчанию 0). Это число соединений будет создано при первом открытии соединения, что сокращает время ожидания при первом обращении

Pooling

При значении true (по умолчанию) соединение выводится из соответствующего пула или, при необходимости, создается и добавляется в соответствующий пул

Connection Lifetime

Указывает временной интервал в секундах. Если соединение возвращено в пул и его время подключение превысило указанное время жизни, оно будет уничтожено. По умолчанию принято значение 0, что отключает такое поведение. Это средство удобно, когда необходимо повторно использовать большое количество соединений за раз

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

string connectionString = 
    @"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True" +
    "Min Pool Size=10";
    
    // ...
    
    // Получить соединение из пула (если он существует) или 
    // создать пул с 10 соединениями (если нет)
    connection.Open();
    
    // Вернуть соединение в пул
    connection.Close();

Некоторые поставщики включают методы для очистки пула соединений. Например, с SqlConnection можно вызывать статические методы ClearPool() и ClearAllPools(). При вызове ClearPool() предоставляется объект SqlConnection, и все соответствующие соединения удаляются. ClearAllPools() очищает все пулы соединений в текущем домене приложения. Формально эти методы не закрывают соединения, они просто помечают их как недействительные, так что по истечении тайм-аута они будут закрыты во время обычной очистки соединений, несколькими минутами спустя.

Эта функциональность используется редко; обычно единственный случай, когда это имеет смысл — когда известно, что пул полон или подключения стали недействительными (например, в результате перезапуска SQL Server), и нужно избежать появления ошибок.

Пулы соединений SQL Server и Oracle всегда поддерживаются как часть глобальных ресурсов домена приложения. В результате пулы соединений не могут быть повторно использованы между разными веб-приложениями на одном и том же веб-сервере или между веб-приложениями и другими приложениями .NET. По той же причине все соединения теряются при перезапуске домена приложений. (Домены приложений перезапускаются по разным причинам, включая изменение веб-страницы, сборки или конфигурационного файла веб-приложения. Домены приложений также перезапускаются по достижении некоторых порогов; например, IIS может перезапускать домен приложения, использующий большой объем памяти или слишком много запросов в очереди. Оба обстоятельства могут свидетельствовать о деградации производительности домена приложения.)

Пройди тесты
Лучший чат для C# программистов