На самом деле для реализации соединения используются два класса (на самом деле больше, но я упрощаю).
Одним из них является реализация IDbConnection
(SQLConnection
, NpgsqlConnection
, * 1006).* и т. д.), который вы используете в своем коде.Другой - это «реальный» объект соединения, который находится внутри сборки и не виден вашему коду.Сейчас мы назовем это «RealConnection
», хотя его фактическое имя отличается в разных реализациях (например, в Npgsql, где я больше всего знаком с реализацией, класс называется NpgsqlConnector
).
Когда вы создаете IDbConnection
, у него нет RealConnection
.Любая попытка что-то сделать с базой данных потерпит неудачу.Когда вы Open()
это, тогда происходит следующее:
- Если пул включен, и в пуле есть
RealConnection
, удалите его и сделайте его RealConnection
для IDbConnection
. - Если пул включен, а общее количество
RealConnection
существующих объектов превышает максимальный размер, выдается исключение. - В противном случае создайте новый
RealConnection
.Инициализируйте его, что потребует открытия какого-либо сетевого соединения (например, TCP / IP) или дескриптора файла (для чего-то вроде Access), просмотрите протокол базы данных для рукопожатия (зависит от типа базы данных) и авторизуйте соединение.Затем он становится RealConnection
для IDbConnection
.
Операции, выполняемые на IDbConnection
, превращаются в операции, которые RealConnection
выполняет для своего сетевого подключения (или чего-либо еще).Результаты превращаются в объекты, реализующие IDataReader
и т. Д., Чтобы обеспечить согласованный интерфейс для вашего программирования.
Если IDataReader
был создан с CommandBehavior.CloseConnection
, тогда этот обработчик данных получает «право собственности» наRealConnection
.
При вызове Close()
происходит одно из следующих действий:
- Если пул и если пул не заполнен, то объект помещаетсяв очереди для использования с более поздними операциями.
- В противном случае
RealConnection
выполнит все определенные протоколом процедуры для завершения соединения (сигнализируя базе данных, что соединение будет закрыто) и закроет сетьподключение и т. д. Затем объект может выйти из области видимости и стать доступным для сборки мусора.
Исключением может быть случай CommandBehavior.CloseConnection
, в этом случае Close()
или Dispose()
вызывается на IDataReader
, который вызывает это.
Если вы звоните Dispose()
, то происходит то же самое, что и Close()
.Разница в том, что Dispose()
рассматривается как «очистка» и может работать с using
, тогда как Close()
может использоваться в середине срока службы, за которым следует более поздняя Open()
.
Из-за использования объекта RealConnection
и того факта, что они объединены в пул, открывающиеся и закрывающиеся соединения превращаются из чего-то относительно тяжелого в относительно легкое.Следовательно, вместо того, чтобы сохранять открытыми соединения в течение длительного времени, чтобы избежать накладных расходов на их открытие, важно сохранять их открытыми как можно более короткое время, поскольку RealConnection
обрабатывает накладные расходы для вас, ичем быстрее вы их используете, тем эффективнее пулы подключений распределяются между пользователями.
Обратите также внимание, что все в порядке с Dispose()
и IDbConnection
, которые вы уже называли Close()
(этоправило, что всегда должно быть безопасно вызывать Dispose()
, независимо от состояния, даже если оно уже было вызвано).Следовательно, если бы вы вручную вызывали Close()
, все равно было бы хорошо иметь соединение в блоке using
, чтобы отследить случаи, когда возникают исключения перед вызовом Close()
.Единственное исключение - когда вы действительно хотите, чтобы соединение оставалось открытым;скажем, вы возвращали IDataReader
, созданный с помощью CommandBehavior.CloseConnection
, и в этом случае вы не располагаете IDbConnection
, а do утилизируйте считыватель.
Если вам не удастся утилизировать соединение, то RealConnection
не будет возвращен в пул для повторного использования или для процедуры его завершения.Либо пул достигнет своего предела, либо число базовых подключений увеличится до такой степени, что ухудшит производительность и заблокирует создание новых.В конце концов, можно вызвать финализатор на RealConnection
и привести к его исправлению, но финализация только уменьшает урон и не может зависеть от него.(IDbConnection
не нужен финализатор, поскольку RealConnection
содержит неуправляемый ресурс и / или должен завершить работу).
Также разумно предположить, что есть некоторыедругое требование к утилизации, уникальное для реализации IDbConnection
, помимо этого, и его все равно следует утилизировать, даже если анализ вышеизложенного заставляет вас считать, что это не нужно (исключение составляет CommandBehavior.CloseConnection
, когда все бремя утилизации переходит на1091 *, но так же важно располагать этим читателем).