Quelle est la bonne façon de s'assurer qu'une connexion SQL est fermée lorsqu'une exception est levée?

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

  •  02-07-2019
  •  | 
  •  

Question

J'utilise un motif qui ressemble à cela souvent. Je me demande si cela va bien ou s'il existe une meilleure pratique que je ne suis pas en train d'appliquer ici.

Plus précisément, je me pose des questions. dans le cas où une exception est levée, le code que j’ai dans le bloc finally est-il suffisant pour que la connexion soit fermée de manière appropriée?

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();
    }
}
Était-ce utile?

La solution

Enveloppez le code de traitement de votre base de données dans un "utilisant"

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

Autres conseils

.Net Framework conserve un pool de connexions pour une raison. Fais-lui confiance! :) Vous n'avez pas besoin d'écrire autant de code simplement pour vous connecter à la base de données et libérer la connexion.

Vous pouvez simplement utiliser l'instruction 'using' et être assuré que 'IDBConnection.Release ()' fermera la connexion pour vous.

Les "solutions" très élaborées ont tendance à générer des codes erronés. Simple c'est mieux.

Documents MSDN en faire une assez clair ...

  • La méthode Close annule toutes les transactions en attente. Il libère ensuite la connexion au pool de connexions ou ferme la connexion si le regroupement de connexions est désactivé.

Vous n'avez probablement pas (et ne voulez pas) désactiver le regroupement de connexions. Le pool gère donc en dernier état l'état de la connexion après l'appel de "Fermer". Cela peut être important, car vous risquez de ne pas bien comprendre du côté du serveur de base de données toutes les connexions ouvertes.

  • Une application peut appeler Fermer plus d’une fois. Aucune exception n'est générée.

Alors, pourquoi s'embêter à tester pour Closed? Il suffit d'appeler Close ().

  • Fermer et Supprimer sont fonctionnellement équivalents.

C’est pourquoi un utilisant un bloc entraîne une connexion fermée. appeler appelle Dispose pour vous.

  • N'appelez pas Close ou Dispose sur une connexion, un DataReader ou tout autre objet géré dans la méthode Finalize de votre classe.

Conseil de sécurité important. Merci Egon.

J'imagine que par "_SqlConnection.State == ConnectionState.Closed". vous vouliez dire! =.

Cela fonctionnera certainement. Je pense qu'il est plus habituel de contenir l'objet de connexion lui-même dans une instruction using, mais ce que vous avez est utile si vous souhaitez réutiliser le même objet de connexion pour une raison quelconque.

Une chose que vous devriez absolument changer, cependant, est la méthode Dispose (). Vous ne devez pas faire référence à l'objet de connexion dans dispose, car il peut déjà avoir été finalisé à ce stade. Vous devez plutôt suivre le modèle Dispose recommandé.

Depuis que vous utilisez IDisposables de toute façon. Vous pouvez utiliser le mot-clé 'using', ce qui revient à appeler la disposition dans un bloc finally, mais le résultat est meilleur.

Voir cette question pour la réponse:

Fermer et se débarrasser - lequel appeler?

Si votre durée de vie de connexion est un appel de méthode unique, utilisez la fonctionnalité à l'aide de du langage pour assurer le nettoyage correct de la connexion. Tandis qu'un bloc try / finally est fonctionnellement identique, il nécessite plus de code et IMO est moins lisible. Il n'est pas nécessaire de vérifier l'état de la connexion, vous pouvez appeler quand même Dispose et il gérera le nettoyage de la connexion.

Si la durée de vie de votre connexion correspond à celle d'une classe contenante, implémentez IDisposable et nettoyez la connexion dans Dispose .

Placez le code de fermeture de la connexion dans un "Enfin". bloquer comme vous le montrer. Enfin, les blocs sont exécutés avant la levée de l'exception. Utilisation de " using " Le bloc fonctionne tout aussi bien, mais je trouve l'explicite "Enfin". méthode plus claire.

L'utilisation des instructions est ancienne pour beaucoup de développeurs, mais les plus jeunes développeurs ne le savent peut-être pas.

pas besoin d'essayer..enfin autour de "en utilisant", l'utilisation de IS à essayer..finalement

Puis-je suggérer ceci:


    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();
        }
    }

J'espère que cela vous aidera:)

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