Qual è il modo corretto per garantire la chiusura di una connessione SQL quando viene generata un'eccezione?

StackOverflow https://stackoverflow.com/questions/141204

  •  02-07-2019
  •  | 
  •  

Domanda

Uso un modello che assomiglia spesso a questo. Mi chiedo se va bene o se esiste una buona pratica che non sto applicando qui.

Nello specifico mi chiedo; nel caso in cui venga generata un'eccezione, il codice che ho nel blocco finalmente è abbastanza per garantire che la connessione sia chiusa in modo appropriato?

public class SomeDataClass : IDisposable
{
    private SqlConnection _conn;

    //constructors and methods

    private DoSomethingWithTheSqlConnection()
    {
        //some code excluded for brevity

        try
        {
            using (SqlCommand cmd = new SqlCommand(SqlQuery.CountSomething, _SqlConnection))
            {
                _SqlConnection.Open();
                countOfSomething = Convert.ToInt32(cmd.ExecuteScalar());
            }
        }
        finally
        {
            //is this the best way?
            if (_SqlConnection.State == ConnectionState.Closed)
                _SqlConnection.Close();
        }

        //some code excluded for brevity
    }

    public Dispose()
    {
        _conn.Dispose();
    }
}
È stato utile?

Soluzione

Riporta il codice di gestione del tuo database in un " usando "

using (SqlConnection conn = new SqlConnection (...))
{
    // Whatever happens in here, the connection is 
    // disposed of (closed) at the end.
}

Altri suggerimenti

Il .Net Framework gestisce un pool di connessioni per un motivo. Fidati! :) Non devi scrivere così tanto codice solo per connetterti al database e rilasciare la connessione.

Puoi semplicemente usare l'istruzione "using" e stare certo che "IDBConnection.Release ()" chiuderà la connessione per te.

Le "soluzioni" altamente elaborate tendono a generare codice errato. Semplice è meglio.

Documenti MSDN rendono questo abbastanza chiaro ...

  • Il metodo Chiudi ripristina tutte le transazioni in sospeso. Rilascia quindi la connessione al pool di connessioni o chiude la connessione se il pool di connessioni è disabilitato.

Probabilmente non hai (e non vuoi) disabilitare il pool di connessioni, quindi alla fine il pool gestisce lo stato della connessione dopo aver chiamato " Close " ;. Questo potrebbe essere importante poiché potresti essere confuso guardando dal lato del server database tutte le connessioni aperte.


  • Un'applicazione può chiamare Chiudi più di una volta. Non viene generata alcuna eccezione.

Quindi perché preoccuparsi di testare per Closed? Basta chiamare Close ().


  • Close e Dispose sono funzionalmente equivalenti.

Questo è il motivo per cui un blocco usando provoca una connessione chiusa. utilizzando chiama Dispose per te.


  • Non chiamare Close o Dispose su una connessione, un DataReader o qualsiasi altro oggetto gestito nel metodo Finalize della tua classe.

Importante consiglio di sicurezza. Grazie, Egon.

Suppongo che da " _SqlConnection.State == ConnectionState.Closed " intendevi! =.

Questo funzionerà sicuramente. Penso che sia più consuetudine contenere l'oggetto connessione stesso all'interno di un'istruzione using, ma quello che hai è buono se vuoi riutilizzare lo stesso oggetto connessione per qualche motivo.

Una cosa che dovresti assolutamente cambiare, però, è il metodo Dispose (). Non è necessario fare riferimento all'oggetto connessione in dispose, poiché potrebbe essere già stato finalizzato a quel punto. Dovresti invece seguire il modello Dispose raccomandato.

Dato che stai usando IDisposables comunque. Puoi usare la parola chiave "using", che equivale sostanzialmente a chiamare dispose in un blocco finally, ma ha un aspetto migliore.

Vedi questa domanda per la risposta:

Chiudi e elimina - quale chiamare?

Se la durata della connessione è una singola chiamata di metodo, utilizzare la funzione using della lingua per garantire la corretta pulizia della connessione. Mentre un blocco try / finally è funzionalmente lo stesso, richiede più codice e IMO è meno leggibile. Non è necessario controllare lo stato della connessione, puoi chiamare Dispose indipendentemente e gestirà la pulizia della connessione.

Se la durata della connessione corrisponde alla durata di una classe contenente, implementare IDisposable e ripulire la connessione in Dispose .

Inserisci il codice di chiusura della connessione in un " Infine " bloccare come si mostra. Infine, i blocchi vengono eseguiti prima che venga generata l'eccezione. Utilizzando un " usando " il blocco funziona altrettanto bene, ma trovo l'esplicito " Infine " metodo più chiaro.

L'uso delle dichiarazioni è un cappello vecchio per molti sviluppatori, ma gli sviluppatori più giovani potrebbero non saperlo a mano.

non c'è bisogno di provare..finalmente intorno a " usando " ;, l'uso È un try..finally

Potrei suggerire questo:


    class SqlOpener : IDisposable
    {
        SqlConnection _connection;

        public SqlOpener(SqlConnection connection)
        {
            _connection = connection;
            _connection.Open();

        }

        void IDisposable.Dispose()
        {
            _connection.Close();
        }
    }

    public class SomeDataClass : IDisposable
    {
        private SqlConnection _conn;

        //constructors and methods

        private void DoSomethingWithTheSqlConnection()
        {
            //some code excluded for brevity
            using (SqlCommand cmd = new SqlCommand("some sql query", _conn))
            using(new SqlOpener(_conn))
            {
                int countOfSomething = Convert.ToInt32(cmd.ExecuteScalar());
            }
            //some code excluded for brevity
        }

        public void Dispose()
        {
            _conn.Dispose();
        }
    }

Spero che aiuti :)

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