«Ouvrir / fermer» SqlConnection ou rester ouvert?

122

J'ai ma logique métier implémentée dans des classes statiques simples avec des méthodes statiques. Chacune de ces méthodes ouvre / ferme la connexion SQL lorsqu'elle est appelée:

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

        // ...

        connection.Close();
    }
}

Mais je pense qu'éviter d'ouvrir et de fermer une connexion économise les performances . J'ai fait quelques tests il y a très longtemps avec la classe OleDbConnection ( je ne suis pas sûr de SqlConnection), et cela a vraiment aidé à fonctionner comme ça (pour autant que je me souvienne):

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

La question est donc: dois-je choisir la méthode (a) ou la méthode (b)? J'ai lu sur une autre question de stackoverflow que le pool de connexions a économisé les performances pour moi, je n'ai pas à me soucier du tout ...

PS. C'est une application ASP.NET - les connexions n'existent que pendant une requête Web. Pas une application ou un service gagnant.

Alex
la source
1
Juste un conseil: utilisez l' DbConnection.StateChangeévénement pour surveiller les changements dans le changement d'état de la connexion (et peut être stocké localement) au lieu de vérifier DbConnection.Statedirectement la propriété. Cela vous fera économiser sur les coûts de performance.
décyclone
1
Un détail qui manque est la façon dont cette méthode fait partie d'une demande de page. Est-ce la seule méthode appelée ou est-ce, comme je l'ai supposé dans ma réponse, l'une des nombreuses méthodes appelées dans une demande de page, cela affecte la bonne réponse;)
David Mårtensson
David - BEAUCOUP de méthodes comme celle-ci sont appelées :)
Alex
1
Le cas A montre un manque de croyance en Dispose: voir stackoverflow.com/questions/1195829/… et l'exemple sur MSDN msdn.microsoft.com/en-us/library/…
user2864740

Réponses:

82

Tenez-vous-en à l'option a .

Le pool de connexions est votre ami.

Adriaan Stander
la source
37
IMHO - il ne devrait même pas fermer. la disposition le fera.
Royi Namir
2
@RoyiNamir J'aime un peu l'appel pour fermer la connexion. Surtout pour les débutants et les nouveaux arrivants à une base de code. C'est plus explicite et lisible.
edhedges
27
@edhedges Utiliser à la fois "using" et Close () ne fera finalement que semer la confusion chez les nouveaux arrivants. Ils ne comprendront pas le but de l'utilisation de «l'utilisation». N'utilisez pas «Fermer» à la place, apprenez-leur le but de «utiliser». Pour qu'ils puissent apprendre, s'améliorer et appliquer ce qu'ils ont appris à d'autres parties du code.
Luis Perez
1
Est-ce que "Open ()" doit / doit être appelé? Je l'utilise actuellement comme ceci: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); }
ganders le
79

Utilisez la méthode (a) à chaque fois. Lorsque vous commencez à mettre à l'échelle votre application, la logique qui traite de l'état deviendra une vraie douleur si vous ne le faites pas.

Le regroupement de connexions fait ce qu'il dit sur l'étain. Pensez simplement à ce qui se passe lorsque l'application évolue et à quel point il serait difficile de gérer manuellement l'état d'ouverture / fermeture de la connexion. Le pool de connexions fait un excellent travail pour gérer automatiquement cela. Si vous êtes préoccupé par les performances, pensez à une sorte de mécanisme de cache mémoire afin que rien ne soit bloqué.

WeNeedAnswers
la source
33

Fermez toujours les connexions dès que vous en avez terminé, afin que la connexion à la base de données sous-jacente puisse revenir dans le pool et être disponible pour les autres appelants. Le regroupement de connexions est assez bien optimisé, il n'y a donc pas de pénalité notable pour cela. Le conseil est fondamentalement le même que pour les transactions - soyez bref et fermez lorsque vous avez terminé.

Cela devient plus compliqué si vous rencontrez des problèmes MSDTC en utilisant une seule transaction autour du code qui utilise plusieurs connexions, auquel cas vous devez en fait partager l'objet de connexion et le fermer uniquement une fois la transaction terminée.

Cependant, vous faites les choses à la main ici, vous voudrez peut-être étudier des outils qui gèrent les connexions pour vous, comme DataSets, Linq to SQL, Entity Framework ou NHibernate.

Neil Barnwell
la source
Vous ne devez pas normalement ouvrir et fermer une connexion dans chaque appel de méthode, une seule fois pour chaque demande de page. C'est ce que j'ai appris au moins;) Temps d'ouverture et de fermeture.
David Mårtensson
8
@David Martensson - les connexions ne sont pas réellement ouvertes et fermées lorsque vous appelez SqlConnection.Open. ASP.NET recycle les connexions actives du pool lorsque la chaîne de connexion correspond à une chaîne de connexion précédemment utilisée. La surcharge impliquée dans ceci est sans conséquence, et en outre, essayer de «faire vous-même» signifie que vous devez assumer toutes les tâches de gestion pour vous assurer que la connexion est toujours active pour chaque utilisation ultérieure, ce qui ajoute de la complexité et des frais généraux. Avec le regroupement de connexions, la meilleure pratique consiste à l'ouvrir et à le fermer pour chaque utilisation.
Jamie Treworgy
2
Avec tout mon respect, la réponse «Toujours des liens étroits» ne correspond pas très bien à la question ... Je les ferme. La question est - quand.
Alex
@David Martensson "Une fois pour chaque page" est simplifié à l'extrême. Vous avez raison de dire que si vous avez plusieurs commandes de base de données à exécuter l'une après l'autre, vous pouvez garder la connexion ouverte pendant que vous les exécutez. Il y aurait une surcharge mineure si vous fermiez et rouvriez - la connexion irait dans le pool et y serait récupérée un instant plus tard.
Concrete Gannet
1
@David Martensson Mais ne gardez jamais une connexion inactive. Si vous attendez une action de l'utilisateur ou quoi que ce soit d'autre, fermez-le. En cas de doute, fermez-le. Vous ouvrez aussi tard que vous le pouvez dans l'espoir que quelqu'un d'autre a fini avec une connexion et l'a mise en commun. Ensuite, vous rendez la faveur - fermez dès que vous le pouvez raisonnablement.
Concrete Gannet
13

Avertissement: je sais que c'est vieux, mais j'ai trouvé un moyen facile de démontrer ce fait, alors je mets ma valeur de deux cents.

Si vous avez du mal à croire que la mise en commun va vraiment être plus rapide, essayez ceci:

Ajoutez ce qui suit quelque part:

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

Maintenant, remplacez tous les appels Open()par TimedOpen()et exécutez votre programme. Maintenant, pour chaque chaîne de connexion distincte que vous avez, la fenêtre de la console (sortie) aura une seule longue ouverture ouverte, et un tas d' ouvertures très rapides.

Si vous souhaitez les étiqueter, vous pouvez ajouter new StackTrace(true).GetFrame(1) +à l'appel à WriteLine.

Chris Pfohl
la source
9

Il existe des distinctions entre les connexions physiques et logiques. DbConnection est une sorte de connexion logique et utilise une connexion physique sous-jacente à Oracle. Fermer / ouvrir DbConnection n'affecte pas vos performances, mais rend votre code propre et stable - les fuites de connexion sont impossibles dans ce cas.

Vous devez également vous rappeler des cas où il existe des limitations pour les connexions parallèles sur le serveur de base de données - en tenant compte de cela, il est nécessaire de rendre vos connexions très courtes.

Le pool de connexions vous libère de la vérification de l'état de la connexion - il suffit de les ouvrir, de les utiliser et de les fermer immédiatement.

Tony Kh
la source
Oui, la connexion n'est pas la connexion - c'est-à-dire que DbConnection n'est pas la connexion physique. DbConnection est une classe .NET qui fournit des méthodes et des propriétés pour manipuler la connexion physique sous-jacente.
Concrete Gannet
Malheureusement, il n'a pas été immédiatement évident que tout cela a été fait implicitement, mais la documentation élabore là-dessus. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat
2

Normalement, vous devriez garder une connexion pour chaque transaction (pas de calculs parallèles)

Par exemple, lorsque l'utilisateur exécute une action de facturation, votre application doit d'abord trouver le solde de l'utilisateur et le mettre à jour, il doit utiliser la même connexion.

Même si ado.net a son pool de connexions, le coût de la connexion est très faible, mais la réutilisation de la connexion est un meilleur choix.

Pourquoi ne pas garder une seule connexion dans l'application

Étant donné que la connexion se bloque lorsque vous exécutez une requête ou une commande, cela signifie que votre application n'effectue qu'une seule opération de base de données à la même heure, quelles sont les performances médiocres.

Un autre problème est que votre application aura toujours une connexion même si votre utilisateur vient de l'ouvrir mais aucune opération.S'il y a de nombreux utilisateurs qui ouvrent votre application, le serveur db coûtera bientôt toute sa source de connexion alors que vos utilisateurs ne l'ont pas fait n'importe quoi.

BrillantRush
la source