SqlConnection “apri / chiudi” o tieni aperto?


122

Ho implementato la mia logica aziendale in semplici classi statiche con metodi statici. Ciascuno di questi metodi apre / chiude la connessione SQL quando viene chiamato:

public static void DoSomething(string something)
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();

        // ...

        connection.Close();
    }
}

Ma penso che evitare di aprire e chiudere una connessione salvi le prestazioni . Ho fatto alcuni test molto tempo fa con la classe OleDbConnection (non sono sicuro di SqlConnection), e sicuramente ha aiutato a funzionare in questo modo (per quanto ricordo):

//pass the connection object into the method
public static void DoSomething(string something, SqlConnection connection)
{
    bool openConn = (connection.State == ConnectionState.Open);
    if (!openConn)
    {
        connection.Open();
    }

    // ....

    if (openConn) 
    {
        connection.Close();
    }
}

Quindi la domanda è: devo scegliere il metodo (a) o il metodo (b)? Ho letto su un'altra domanda di stackoverflow che il pool di connessioni mi ha salvato le prestazioni, non devo preoccuparmi affatto ...

PS. È un'app ASP.NET: le connessioni esistono solo durante una richiesta web. Non una win-app o un servizio.


1
Solo un consiglio: usa l' DbConnection.StateChangeevento per monitorare i cambiamenti nel cambiamento di stato della connessione (e può essere archiviato localmente) invece di controllare DbConnection.Statedirettamente la proprietà. Ti farà risparmiare sui costi delle prestazioni.
deciclone

1
Un dettaglio che manca è il modo in cui questo metodo fa parte di una richiesta di pagina. È l'unico metodo chiamato o è, come presumo nella mia risposta, uno dei tanti metodi chiamati in una richiesta di pagina, influisce sulla risposta corretta;)
David Mårtensson

David - MOLTI metodi come questo vengono chiamati :)
Alex

1
Caso A mostra una mancanza di fede in Dispose: vedi stackoverflow.com/questions/1195829/... e l'esempio su MSDN msdn.microsoft.com/en-us/library/...
user2864740

Risposte:


82

Attenersi all'opzione a .

Il pool di connessioni è tuo amico.


37
IMHO - non dovrebbe nemmeno avvicinarsi. lo smaltimento lo farà.
Royi Namir

2
@RoyiNamir Mi piace la chiamata per chiudere la connessione. Soprattutto per principianti e principianti in una base di codice. È più esplicito e leggibile.
edhedges

27
@edhedges L'utilizzo sia di "using" che di Close () alla fine causerà solo confusione per i nuovi arrivati. Non capiranno lo scopo dell'utilizzo di "utilizzo". Non usare "Chiudi" invece insegna loro lo scopo di "usare". In modo che possano imparare, migliorare e applicare ciò che apprendono ad altre parti del codice.
Luis Perez

1
Dovrebbe / deve essere chiamato "Open ()"? Attualmente lo sto usando in questo modo: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); }
Ganders

79

Usa il metodo (a), ogni volta. Quando inizi a ridimensionare la tua applicazione, la logica che si occupa dello stato diventerà un vero problema se non lo fai.

Il pool di connessioni fa quello che dice sulla latta. Basti pensare a cosa succede quando l'applicazione si ridimensiona e quanto sarebbe difficile gestire manualmente lo stato di apertura / chiusura della connessione. Il pool di connessioni fa un ottimo lavoro nel gestirlo automaticamente. Se sei preoccupato per le prestazioni, pensa a una sorta di meccanismo di cache di memoria in modo che nulla venga bloccato.


33

Chiudi sempre le connessioni non appena hai finito, in modo che la connessione al database sottostante possa tornare nel pool ed essere disponibile per altri chiamanti. Il pool di connessioni è abbastanza ben ottimizzato, quindi non ci sono penalità evidenti per farlo. Il consiglio è fondamentalmente lo stesso delle transazioni: mantienile brevi e chiudi quando hai finito.

Diventa più complicato se stai riscontrando problemi di MSDTC utilizzando una singola transazione attorno al codice che utilizza più connessioni, nel qual caso devi effettivamente condividere l'oggetto connessione e chiuderlo solo una volta completata la transazione.

Comunque tu stia facendo le cose a mano qui, quindi potresti voler indagare sugli strumenti che gestiscono le connessioni per te, come DataSet, Linq to SQL, Entity Framework o NHibernate.


Normalmente non dovresti aprire e chiudere una connessione all'interno di ogni chiamata al metodo, solo una volta per ogni richiesta di pagina. Questo è quello che ho imparato almeno;) L'apertura e la chiusura costano tempo.
David Mårtensson

8
@David Martensson: le connessioni non vengono effettivamente aperte e chiuse quando si chiama SqlConnection.Open. ASP.NET ricicla le connessioni attive dal pool quando la stringa di connessione corrisponde a una stringa di connessione utilizzata in precedenza. L'overhead coinvolto in questo è irrilevante e, inoltre, provare a "farlo da soli" significa che devi assumerti tutte le attività di gestione per garantire che la connessione sia ancora attiva per ogni utilizzo successivo, il che aggiunge complessità e overhead. Con il pool di connessioni, è consigliabile aprirlo e chiuderlo per ogni utilizzo.
Jamie Treworgy

2
Con tutto il mio rispetto, la risposta "Chiudi sempre le connessioni" non si adatta molto bene alla domanda ... Le chiudo. La domanda è: quando.
Alex

@David Martensson "Una volta per ogni pagina" è troppo semplificato. Hai ragione che se hai diversi comandi di database da eseguire uno dopo l'altro, puoi mantenere la connessione aperta mentre li esegui. Ci sarebbe un piccolo sovraccarico se chiudessi e riaprissi: la connessione andrebbe nel pool e verrebbe recuperata un attimo dopo.
Concrete Gannet

1
@David Martensson Ma non mantenere mai una connessione inattiva. Se stai aspettando un'azione da parte dell'utente o qualsiasi altra cosa, chiudila. In caso di dubbio, chiudilo. Apri il più tardi possibile nella speranza che qualcun altro abbia terminato con un collegamento e lo abbia condiviso. Quindi restituisci il favore - chiudi il prima ragionevolmente possibile.
Concrete Gannet

13

Disclaimer: so che questo è vecchio, ma ho trovato un modo semplice per dimostrarlo, quindi sto mettendo i miei due centesimi.

Se hai difficoltà a credere che il raggruppamento sarà davvero più veloce, prova questo:

Aggiungi quanto segue da qualche parte:

using System.Diagnostics;
public static class TestExtensions
{
    public static void TimedOpen(this SqlConnection conn)
    {
        Stopwatch sw = Stopwatch.StartNew();
        conn.Open();
        Console.WriteLine(sw.Elapsed);
    }
}

Ora sostituisci tutte le chiamate a Open()con TimedOpen()ed esegui il tuo programma. Ora, per ogni stringa di connessione distinta che hai, la finestra della console (output) avrà un'unica apertura di lunga durata e un gruppo di aperture molto veloci.

Se desideri etichettarli, puoi aggiungerli new StackTrace(true).GetFrame(1) +alla chiamata a WriteLine.


9

Esistono distinzioni tra connessioni fisiche e logiche. DbConnection è un tipo di connessione logica e utilizza la connessione fisica sottostante a Oracle. La chiusura / apertura di DbConnection non influisce sulle prestazioni, ma rende il codice pulito e stabile: in questo caso le perdite di connessione sono impossibili.

Inoltre dovresti ricordare i casi in cui ci sono limitazioni per le connessioni parallele sul server db - tenendo conto di ciò è necessario rendere le tue connessioni molto brevi.

Il pool di connessioni ti libera dal controllo dello stato della connessione: aprili, usali e chiudili immediatamente.


Sì, la connessione non è la connessione, ovvero DbConnection non è la connessione fisica. DbConnection è una classe .NET che fornisce metodi e proprietà per manipolare la connessione fisica sottostante.
Concrete Gannet

Sfortunatamente non è stato subito ovvio che tutto ciò fosse fatto implicitamente, ma la documentazione lo approfondisce. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat

2

Normalmente dovresti mantenere una connessione per ogni transazione (nessun calcolo parallelo)

Ad esempio, quando l'utente esegue un'azione di addebito, l'applicazione deve prima trovare il saldo dell'utente e aggiornarlo, dovrebbe utilizzare la stessa connessione.

Anche se ado.net ha il suo pool di connessioni, il costo della connessione di invio è molto basso, ma riutilizzare la connessione è una scelta migliore.

Perché non mantenere solo una connessione nell'applicazione

Poiché la connessione si blocca quando esegui una query o un comando, significa che la tua applicazione sta eseguendo solo un'operazione di database allo stesso tempo, per quanto siano scarse le prestazioni.

Un altro problema è che la tua applicazione avrà sempre una connessione anche se il tuo utente l'ha semplicemente aperta ma nessuna operazione.Se ci sono molti utenti che aprono la tua applicazione, il server db costerà presto tutta la sua fonte di connessione mentre i tuoi utenti non l'hanno fatto nulla.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.