Пул подключений

Последнее обновление: 08.02.2021

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

Пул подключений позволяет использовать ранее созданные подключения. Так, если параметр Pooling в строке подключения равен true (по умолчанию он равен true), то после закрытия подключения с помощью метода Close()/CloseAsync() закрытое подключение возвращается в пул подключений, где оно оно готово к повторному использованию при следующем вызове метода Open()/OpenAsync(). Когда менеджер подключений, который управляет пулом, получает запрос на открытие нового подключения с помощью метода Open()/OpenAsync(), то он проверяет все подключения пула.

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

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

using Microsoft.Data.SqlClient;
using System;
using System.Threading.Tasks;

namespace HelloApp
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using(SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            Console.WriteLine("Программа завершила работу.");
            Console.Read();
        }
    }
}

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

950d8a37-50a8-44e3-8778-ade70e5415d6
950d8a37-50a8-44e3-8778-ade70e5415d6
Программа завершила работу.

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

Все подключения в пуле различаются по нескольким признакам:

  • строка подключения

  • учетные записи, используемые при подключении

  • процесс приложения

В следующем примере в первом и третьем блоках using будет использоваться одно и то же подключение из пула, поскольку строка подключения будет совпадать:

using Microsoft.Data.SqlClient;
using System;
using System.Threading.Tasks;

namespace HelloApp
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string connectionString = "Server=(localdb)\\mssqllocaldb;Database=master;Trusted_Connection=True;";
            string connectionString2 = "Server=(localdb)\\mssqllocaldb;Database=tempdb;Trusted_Connection=True;";

            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            using (SqlConnection connection = new SqlConnection(connectionString2))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            Console.WriteLine("Программа завершила работу.");
            Console.Read();
        }
    }
}

Консольный вывод в моем случае будет следующим:

5df81b79-6229-4ba6-bb46-1671229cb4c1
8c509b49-62ac-4731-892d-16e3a68f5b7e
5df81b79-6229-4ba6-bb46-1671229cb4c1
Программа завершила работу.

Управление пулом

Стоит отметить, что подключение добавляется в пул, если параметр Pooling равен true. Хотя, выше в примерах в строках подключенияя этот параметр не указан, но по умолчанию он равен true. Однако, присвоив значение false, мы можем отключить пуллинг подключения:

using Microsoft.Data.SqlClient;
using System;
using System.Threading.Tasks;

namespace HelloApp
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string connectionString = "Server=(localdb)\\mssqllocaldb;Database=master;Trusted_Connection=True;";
            string connectionString2 = "Server=(localdb)\\mssqllocaldb;Database=tempdb;Trusted_Connection=True;";

            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            using (SqlConnection connection = new SqlConnection(connectionString2))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            Console.WriteLine("Программа завершила работу.");
            Console.Read();
        }
    }
}

В этом случае, несмотря на одну и ту же строку подключения идентификаторы подключения не будут совпадать:

b750fdba-5570-47a1-ac84-471c3cc57813
b0ce7a14-3cb8-48c3-b0a7-31c7a2fbc090
Программа завершила работу.

Кроме того, мы можем в строке подключения указать параметры Max Pool Size и Min Pool Size.

Max Pool Size указывает на максимальное количество подключений, которое может быть добавлено в пул. Может принимать числовое значение начиная с 1, но не мньше значения параметра Min Pool Size. По умолчанию равен 100.

Min Pool Size указывает на минимально допустимое количество подключений, которое может быть добавлено в пул. Может принимать числовое значение начиная с 0, но не больше значения из параметра Max Pool Size. По умолчанию равен 0.

Если параметр Min Pool Size не указан в строке подключения или его значение равно 0, то подключения в пуле будут закрыты после периода отсутствия активности (4-8 минут), либо если разорвана связь с сервером базы данных. Но если значение параметра Min Pool Size больше 0, пул подключений не удаляется, пока не завершится процесс приложения.

Кроме того, класс SqlConnection имеет два статических метода для очистки пула:

  • SqlConnection.ClearPool(connection): удаляет из пула конкретное подключение SqlConnection, которое передается в качестве параметра

  • SqlConnection.ClearAllPools(): полностью очищает пул подключений

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

using Microsoft.Data.SqlClient;
using System;
using System.Threading.Tasks;

namespace HelloApp
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string connectionString = "Server=(localdb)\\mssqllocaldb;Database=master;Trusted_Connection=True;";
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);


                SqlConnection.ClearPool(connection);
            }
            //SqlConnection.ClearAllPools();
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                Console.WriteLine(connection.ClientConnectionId);
            }
            Console.WriteLine("Программа завершила работу.");
            Console.Read();
        }
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850