2009-06-29 5 views
8

Nous avons un code client qui utilise la classe SqlConnection .NET pour parler à une base de données SQL Server. Il échoue par intermittence avec cette erreur:classe .NET SqlConnection, mise en commun de connexion et la logique de rebranchement

« ExecuteReader nécessite une connexion ouverte et disponible l'état actuel de la connexion est fermée. »

La solution « temporaire » est de redémarrer le processus, après quoi tout fonctionne - cependant, c'est évidemment insatisfaisant.

Le code maintient un cache des instances de SqlConnection, une pour chaque base de données.

Nous aimerions réécrire le code, mais avant de le faire, je dois savoir quelques choses:

Ma première question est: est-il inefficace de se connecter de façon répétée et débrancher les objets SqlConnection, ou ne la bibliothèque sous-jacente effectue le regroupement de connexions en notre nom?

// Is this bad/inefficient? 
for(many-times) 
{ 
    using(SQLConnection conn = new SQLConnection(connectionString)) 
    { 
     // do stuff with conn 
    } 
} 

Parce que notre code ne pas faire ce qui précède, ce qui semble la cause probable du problème est que quelque chose arrive à la base de données SQLServer sous-jacente au cours de la « vie » de la connexion qui provoque la connexion à fermer

S'il s'avère qu'il vaut la peine de "mettre en cache" des objets SqlConnection, quelle est la manière recommandée de gérer toutes les erreurs qui pourraient être résolues simplement en "se reconnectant" à la base de données. Je parle de scénarios tels que:

  • La base de données est mis hors ligne et remis en ligne, mais le processus client avait pas de transactions ouvertes alors que ce qui se passait
  • La base de données était « déconnecté », puis « rebranché "

Je remarque qu'il existe une propriété" State "sur SqlConnection ... existe-t-il un moyen approprié d'interroger cela?

Enfin, j'ai une instance de SQL Server de test mis en place avec les droits d'accès: comment puis-je faire pour reproduire l'erreur exacte «ExecuteReader nécessite une connexion ouverte et disponible l'état actuel de la connexion est fermée »

Répondre

19

Non, ce n'est pas inefficace pour créer beaucoup d'objets SqlConnection et fermer chacun d'entre eux lorsque vous avez terminé. C'est exactement la bonne chose à faire. Laissez le pool de connexions .NET framework faire son travail - n'essayez pas de le faire vous-même. Vous n'avez pas besoin de faire quoi que ce soit spécifique pour permettre la connexion mise en commun (bien que vous pouvez le désactiver en réglant Pooling=false dans votre chaîne de connexion).

Il y a beaucoup de choses qui pourraient mal tourner si vous essayez de mettre en cache la connexion vous-même. Il suffit de dire pas :)

+0

Ce que j'espérais entendre ... Des idées sur la façon dont je pourrais reproduire l'erreur exacte que nous voyons? (Juste pour "prouver" que j'ai résolu le problème)? –

+0

Difficile à dire, pour être honnête. Cela pourrait facilement être une condition de concurrence, si vous essayez d'utiliser la même connexion à partir de plusieurs threads. –

+1

Pour désactiver le regroupement de connexions: ajoutez "Pooling = False;" à la chaîne de connexion. – Richard

2

Vous devez activer connection pooling sur votre chaîne de connexion. Dans ce cas, le moteur d'exécution ajoute vos connexions au pool lorsque vous les fermez, au lieu de vraiment déconnecter. Lorsqu'une nouvelle connexion est retirée du pool, elle est réinitialisée (c'est-à-dire que sp_reset_connection est appelée) puis présentée à votre application comme une toute nouvelle connexion. Le pool gère de manière transparente les cas comme si la connexion était fermée pendant la marche au ralenti dans la piscine.Le coût de création d'une nouvelle connexion est important parce que l'authentification nécessite plusieurs allers-retours entre le client et le serveur (selon la méthode d'authentification et les paramètres SSL, il peut être 1 aller-retour dans le meilleur des cas contre environ 10 dans pire).

Et pour répondre à votre question, connectez-vous à l'événement OnStateChange lorsque son état change, mais cela ne devrait pas vous intéresser si vous utilisez le regroupement.

+0

Le pool de connexion est la valeur par défaut, vous n'avez rien à faire pour l'activer. Vous pouvez le désactiver, mais c'est une exigence rare. – Richard

+1

Veuillez noter que si le regroupement de connexions est activé et que vous ouvrez une connexion pour vérifier si une base de données existe, puis créez la base de données en fonction de ces informations. Ensuite, l'astuce sp_reset_connection ne vous permettra pas de voir la base de données. Donc, faites la première connexion sans connexion de connexion. –

1

Dans mon expérience récente si vous utilisez ce code:

using(SQLConnection conn = new SQLConnection(connectionString)) 
{ 
    // do stuff with conn 
} 

ont une erreur, et ne fermez pas explicitement la connexion, il ne sera pas fermé ou réintégrée dans la piscine. Alors utilisez un catch ou enfin un bloc pour fermer la connexion

Questions connexes