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

d{ "title": "Управление пулом соединений в Delphi: технические аспекты и реализация", "keywords": "пул соединений Delphi, TThreadPool, TSQLConnection, управление подключениями, многопоточность Delphi, ADO пул, dbExpress пул, FireDAC пул соединений", "description": "Техническая реализация управления пулом соединений в Delphi: отличия ADO, dbExpress и FireDAC, спецификация TThreadPool, параметры настройки, стандарты качества соединений.", "html_content": "

Материалы и внутренняя архитектура пула соединений в Delphi

\n\n

Пул соединений в Delphi представляет собой контейнер предварительно инициализированных подключений к базе данных. В отличие от классического подхода (создание/уничтожение TSQLConnection или TADOConnection на каждый запрос), пул хранит живые сокеты или сессии, что устраняет накладные расходы на трехстороннее рукопожатие TCP (SYN, SYN-ACK, ACK) и аутентификацию (для Firebird — инициализация isc_database_connect занимает 40–120 мс в зависимости от версии ОС). Материальная база — объекты TPooledConnection (для dbExpress) или TFDConnection.SpecifyPool (для FireDAC), которые хранят ссылку на физический канал. Каждый объект занимает от 4 КБ (пустой ADO-пул) до 16 КБ (FireDAC с кэшем метаданных) в памяти процесса.

\n\n

Спецификации и параметры настройки

\n\n

Технические характеристики пула регулируются через набор директив:

\n\n\n

Отличия реализации ADO, dbExpress и FireDAC

\n\n

ADO (dbGo) использует встроенный механизм Microsoft OLEDB Session Pooling. При создании TADOConnection флаг KeepConnection := True включает пул на стороне провайдера (SQLNCLI11.1). Недостаток — невозможность управления размером из Delphi (MaxPoolSize задается строкой подключения «Connection Pool Size=10»). Каждый TDataSet.Open вызывает QueryInterface у пула, что в 64-битных сборках приводит к утечкам при частом закрытии/открытии (из-за неправильного подсчета ссылок в интерфейсе IDBCreateSession).

\n\n

dbExpress (TSQLConnection) — собственная реализация на уровне TSQLConnectionPool. Хранит пул как TList, где каждый элемент содержит сокет (для InterBase — fSocketTCPServer). В отличие от ADO, dbExpress не поддерживает реконнект при разрыве канала (отсутствует команда ALTER SESSION). Качество соединений контролируется через TSQLMonitor.OnTrace, который логирует коды ошибок Winsock (например, WSAECONNABORTED).

\n\n

FireDAC — наиболее продвинутый вариант. Пуловые соединения хранятся в TFDCustomConnection.Driver.Pool, который использует ConcurrentHashMap для потокобезопасности. Отличительная особенность — TFDPoolManager.OnValidate, вызываемый при каждом checkout (выборка соединения из пула). Внутри выполняется ping-запрос к СУБД (SELECT 1 для MySQL, EXECUTE BLOCK для Firebird). Если ping проваливается, соединение помечается как stale и уничтожается физически (freeConnection). Стандартная реализация использует критическую секцию с спин-локом (FAFCriticalSection), что на многоядерных системах (Core i7-12700K) дает задержку 0.2–1.5 мкс на захват.

\n\n

Материалы сборки и качество стандартов

\n\n

При разработке собственного пула (например, на основе TThreadedQueue и TDatabaseLoginDialog) необходимо соблюдать стандарты:

\n\n\n

Различия в управлении временем жизни

\n\n

В ADO каждый объект TADOConnection создает внутренний дескриптор, который живет до вызова Close. В FireDAC физическое соединение может быть переиспользовано даже после вызова Disconnect, если пул активен (свойство Pooled := True). Это критично для мобильных сборок (Android API 30+), где эмуляция SQLite через ICS-драйвер имеет лимит в 2 одновременных подключения. dbExpress в этом случае выбрасывает исключение EDBXConnectionLost, а FireDAC корректно ждет освобождения слота (вызов Sleep(50) в цикле Repeat-Until). Разница в поведении связана с тем, что FireDAC использует WaitForMultipleObjects для ожидания свободного слота, тогда как dbExpress использует busy-wait с вызовом ProcessMessages, что приводит к 100% загрузке одного ядра при высоком конкурентном спросе (более 10 потоков на одном TSQLConnectionPool).

\n\n

Пример технической реализации на FireDAC

\n\n

Базовая настройка в коде (без визуальных компонентов):

\n" }

Добавлено: 27.04.2026