Domanda

Stavo cercando di spiegare a qualcuno il perché connessioni al database implementare IDisposable, quando mi sono reso conto che non so davvero cosa significhi effettivamente "aprire una connessione".
Quindi la mia domanda è: cosa fa praticamente C# quando apre una connessione?

Grazie.

È stato utile?

Soluzione

In realtà ci sono due classi coinvolte nell'implementazione di una connessione (in realtà di più, ma sto semplificando).

Uno di questi è il IDbConnection implementazione (SQLConnection, NpgsqlConnection, OracleConnection, ecc.) utilizzati nel codice.L'altro è un oggetto di connessione "reale" interno all'assembly e non visibile al codice.Lo chiameremo "RealConnection" per ora, anche se il suo nome effettivo differisce a seconda delle diverse implementazioni (ad es.in Npgsql, che è il caso in cui ho più familiarità con l'implementazione, la classe viene chiamata NpgsqlConnector).

Quando crei il tuo IDbConnection, non ha a RealConnection.Qualsiasi tentativo di fare qualcosa con il database fallirà.Quando tu Open() allora accade quanto segue:

  1. Se il pooling è abilitato ed è presente un file RealConnection in piscina, dequealo e fallo diventare il RealConnection per il IDbConnection.
  2. Se il pooling è abilitato e il numero totale di RealConnection gli oggetti esistenti sono più grandi della dimensione massima, genera un'eccezione.
  3. Altrimenti creane uno nuovo RealConnection.Inizializzalo, il che comporterà l'apertura di una sorta di connessione di rete (ad es.TCP/IP) o l'handle di file (per qualcosa come Access), passare attraverso il protocollo del database per l'handshake (varia in base al tipo di database) e autorizzare la connessione.Questo diventa quindi il RealConnection per il IDbConnection.

Operazioni effettuate sul IDbConnection vengono trasformati in operazioni il RealConnection fa sulla sua connessione di rete (o qualsiasi altra cosa).I risultati vengono trasformati in oggetti di implementazione IDataReader e così via in modo da fornire un'interfaccia coerente per la tua programmazione.

Se un IDataReader è stato creato con CommandBehavior.CloseConnection, allora quel lettore di dati ottiene la "proprietà" del file RealConnection.

Quando chiami Close() allora accade una delle seguenti cose:

  1. In caso di pooling e se il pool non è pieno, l'oggetto viene inserito nella coda per essere utilizzato con operazioni successive.
  2. Altrimenti il RealConnection eseguirà tutte le procedure definite dal protocollo per terminare la connessione (segnalando al database che la connessione verrà interrotta) e chiuderà la connessione di rete, ecc.L'oggetto può quindi uscire dall'ambito e diventare disponibile per la Garbage Collection.

L'eccezione sarebbe se il CommandBehavior.CloseConnection caso è successo, nel qual caso è Close() O Dispose() essere chiamato su IDataReader che innesca questo.

Se chiami Dispose() allora succede la stessa cosa come da Close().La differenza è questa Dispose() è considerato come "pulizia" e può funzionare con using, Mentre Close() potrebbe essere utilizzato nel mezzo della vita e seguito da un periodo successivo Open().

A causa dell'uso del RealConnection oggetto e il fatto che siano raggruppati, l'apertura e la chiusura delle connessioni cambia da qualcosa di relativamente pesante a relativamente leggero.Quindi, anziché essere importante mantenere aperte le connessioni per un lungo periodo per evitare il sovraccarico della loro apertura, diventa importante mantenerle aperte il più breve tempo possibile, poiché il RealConnection si occupa del sovraccarico per te e quanto più rapidamente li usi, tanto più efficientemente le connessioni in pool vengono condivise tra gli usi.

Nota anche che va bene Dispose() UN IDbConnection che hai già chiamato Close() attivo (è una regola che dovrebbe essere sempre sicuro chiamare Dispose(), qualunque sia lo Stato, anzi anche se già chiamato).Quindi se stavi chiamando manualmente Close() sarebbe comunque bene avere la connessione in a using block, per individuare i casi in cui si verificano eccezioni prima della chiamata a Close().L'unica eccezione è dove desideri effettivamente che la connessione rimanga aperta;dì che stavi restituendo un IDataReader creato con CommandBehavior.CloseConnection, nel qual caso non smaltisci il IDbConnection, Ma Fare disporre il lettore.

Se non riesci a eliminare la connessione, allora il file RealConnection non verrà restituito al pool per il riutilizzo né verrà sottoposto alla procedura di spegnimento.O il pool raggiungerà il suo limite oppure il numero di connessioni sottostanti aumenterà al punto da danneggiare le prestazioni e impedirne la creazione.Alla fine il finalizzatore si accende RealConnection può essere chiamato e portare alla risoluzione del problema, ma la finalizzazione riduce solo il danno e non si può fare affidamento su di esso.(IL IDbConnection non ha bisogno di un finalizzatore, poiché è il file RealConnection che detiene la risorsa non gestita e/o deve effettuare l'arresto).

È anche ragionevole presupporre che esista qualche altro requisito di smaltimento esclusivo per l'implementazione del file IDbConnection oltre questo, e dovrebbe comunque essere smaltito anche se l'analisi di quanto sopra porta a ritenere che non sia necessario (l'eccezione è quando CommandBehavior.CloseConnection trasferisce tutti gli oneri di smaltimento al IDataReader, ma poi è altrettanto importante smaltire quel lettore).

Altri suggerimenti

Buona domanda.

Dal mio (conoscenza un po 'limitata) del "under-the-hood" di lavoro di una connessione SQL, sono coinvolti molti passi, come ad esempio:

Piazza di Under the Hood

  1. presa fisico / tubo viene aperto (utilizzando trovati conducenti, ad esempio ODBC)
  2. Stretta di mano con SQL Server
  3. stringa di connessione / credenziali negoziato
  4. Transaction scoping

Per non menzionare il collegamento pooling, credo che ci sia una sorta di alogrithm coinvolti (se la stringa di connessione corrisponde a uno per una piscina già esistente, il collegamento si aggiunge al pool, altrimenti ne viene creato)

IDiposable

Per quanto riguarda le connessioni SQL, abbiamo implementare IDisposable in modo che quando si chiama Dispose (sia tramite la direttiva using o esplicitamente), pone la parte posteriore di collegamento nella pool di connessioni. Ciò è in netto contrasto con appena il vecchio SQLConnection.close pianura () -. Come tutto questo non fa altro che chiuderlo temporaneamente, ma le riserve che la connessione per un uso successivo

Dalla mia comprensione, .Close () chiude la connessione al database, mentre .Dispose () chiama .Close (), e , quindi Libera risorse non gestite.

Quei punti in mente, per lo meno è buona norma per implementare IDisposable.

Aggiunta di risposte di cui sopra ... La chiave è quella sulla "apertura della connessione" risorse possono essere assegnate che avrà più di garbage collection standard per recuperare, cioè un open presa / tubo / IPC di somekind. Il metodo Dispose () pulisce questi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top