Question

Je tente d'expliquer à quelqu'un pourquoi Connexions de base de données mettre en œuvre IDisposable, quand je réalise que je ne sais pas vraiment ce que « l'ouverture d'une connexion » en fait moyenne.
Donc, ma question est - Qu'est-ce que c # faire pratiquement quand il ouvre une connexion?

Merci.

Était-ce utile?

La solution

Il y a en fait deux classes impliquées dans la mise en œuvre d'une connexion (en fait plus, mais je simplifie).

L'un d'entre eux est la mise en œuvre de IDbConnection (SQLConnection, NpgsqlConnection, OracleConnection, etc.) que vous utilisez dans votre code. L'autre est un objet de connexion « réel » qui est interne à l'assemblée, et non visible à votre code. Nous appellerons « RealConnection » pour l'instant, bien que son nom diffère de réelles avec différentes implémentations (par exemple dans Npgsql, ce qui est le cas où je suis plus familier avec la mise en œuvre, la classe est appelée NpgsqlConnector).

Lorsque vous créez votre IDbConnection, il ne dispose pas d'un RealConnection. Toute tentative de faire quelque chose avec la base de données échouera. Lorsque vous Open() il alors le suivant se produit:

  1. Si la mise en commun est activé, et il y a un RealConnection dans la piscine, deque et en font le RealConnection pour le IDbConnection.
  2. Si la mise en commun est activé, et le nombre total d'objets RealConnection existants est plus grande que la taille maximale, lancer une exception.
  3. Sinon, créez un nouveau RealConnection. Initialiser, ce qui impliquera l'ouverture d'une sorte de connexion réseau (par exemple TCP / IP) ou descripteur de fichier (pour quelque chose comme Access), passer par le protocole de la base de données poignées de main (varie selon le type de base de données) et autoriser la connexion. Cela devient alors le RealConnection pour le IDbConnection.

opérations effectuées sur l'IDbConnection sont transformées en opérations le RealConnection fait sur sa connexion réseau (ou autre). Les résultats sont transformés en objets d'application IDataReader et ainsi de suite de façon à donner une interface cohérente pour votre programmation.

Si un IDataReader a été créé avec CommandBehavior.CloseConnection, alors que datareader obtient la "propriété" du RealConnection.

Lorsque vous appelez Close() alors l'un des événements suivants se produisent:

  1. Si la mise en commun, et si la piscine est pas plein, l'objet est placé dans la file pour les opérations ultérieures.
  2. Sinon, le RealConnection procédera à des procédures définis par le protocole pour mettre fin à la connexion (signalisation à la base de données que la connexion va fermer) et ferme la connexion réseau, etc. L'objet peut alors tomber hors de portée et de devenir disponibles pour la collecte des ordures.

L'exception serait si le cas de CommandBehavior.CloseConnection est arrivé, auquel cas il Close() ou de Dispose() appelé le IDataReader qui déclenche cela.

Si vous appelez Dispose() alors la même chose se passe comme par Close(). La différence est que Dispose() est considérée comme « nettoyage » et peut travailler avec using, tandis que Close() pourrait être utilisé au milieu de la vie, et suivie d'une Open() plus tard.

En raison de l'utilisation de l'objet RealConnection et le fait qu'ils sont mis en commun, les connexions ouverture et la fermeture des changements d'être quelque chose relativement lourd à relativement léger. Par conséquent, plutôt que qu'il soit important de garder les connexions ouvertes pendant une longue période pour éviter la surcharge de les ouvrir, il devient important de les garder ouverts pour le temps d'une courte possible, étant donné que les offres de RealConnection avec les frais généraux pour vous, et plus rapidement vous les utilisez, plus efficacement les connexions mises en commun sont partagés entre les utilisations.

Notez également qu'il est correct de Dispose() un IDbConnection que vous avez déjà appelé Close() sur (c'est une règle selon laquelle il doit toujours être sûr d'appeler Dispose(), quel que soit l'état, en effet, même si elle était déjà appelé). Par conséquent, si vous appeliez manuellement Close() il serait toujours bon d'avoir la connexion dans un usingbloc, pour attraper les cas où des exceptions se produisent avant l'appel à Close(). La seule exception est l'endroit où vous voulez réellement la connexion à rester ouvert; dites que vous reveniez un IDataReader créé avec CommandBehavior.CloseConnection, auquel cas vous ne disposez pas IDbConnection, mais ne disposer le lecteur.

Si vous omettez de disposer de la connexion, le RealConnection ne sera pas retourné à la piscine pour la réutilisation, ou passer par la procédure d'arrêt. Soit la piscine atteindra sa limite, ou le nombre de connexions sous-jacentes augmentera au point de nuire à la performance et bloquer plus d'être créé. Finalement, le Finaliser sur RealConnection peut être appelé et conduit à celle-ci étant fixé, mais la finalisation ne fait que réduire les dégâts et ne peut compter sur lui. (Le IDbConnection n'a pas besoin Finaliser, car il est le RealConnection qui détient la ressource non gérée et / ou doit faire l'arrêt).

Il est également raisonnable de supposer qu'il existe une autre exigence pour l'élimination unique à la mise en œuvre du IDbConnection au-delà, et il devrait encore être mis au rebut, même si l'analyse des vous mène au-dessus de croire son pas nécessaire (l'exception est quand CommandBehavior.CloseConnection passe tout le fardeau de l'élimination au IDataReader, mais il est tout aussi important de disposer que le lecteur).

Autres conseils

Bonne question.

De mon (peu connaissance limitée) du « sous le capot » travail d'une connexion SQL, plusieurs étapes sont impliqués, tels que:

Les étapes sous le capot

  1. douille / physique tuyau est ouvert (en utilisant les pilotes donnés, par exemple ODBC)
  2. Handshake avec SQL Server
  3. Chaîne de connexion / lettres de créance négocié
  4. détermination de la portée de la transaction

Sans parler de la mise en commun de connexion, je crois qu'il ya une sorte de alogrithm impliqué (si la chaîne de connexion correspond à un pour une piscine déjà existante, la connexion est ajouté à la piscine, sinon nouveau est créé)

IDiposable

En ce qui concerne les connexions SQL, nous mettons en œuvre IDisposable de sorte que lorsque nous appelons Éliminez (soit par la directive à l'aide ou explicity), il place à l'arrière de connexion dans le pool de connexion. Ceci est en contraste frappant avec juste la plaine vieux SQLConnection.close () -. Que tout cela ne se trouve à proximité temporairement, mais les réserves que la connexion pour une utilisation ultérieure

De ma compréhension, .Close () ferme la connexion à la base de données, alors que .Dispose () appelle .Close (), et puis Communiqués ressources non gérées.

Les points à l'esprit, à tout le moins, il est bon de mettre en œuvre IDisposable.

Ajout de réponses ci-dessus ... La clé est que sur les ressources « ouverture de la connexion » peuvent être attribués que prendra plus de la collecte des ordures standard pour récupérer, à savoir un socket ouvert / tuyau / IPC de somekind. La méthode Dispose () nettoie ces vers le haut.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top