2008-12-05 6 views
2

Nous avons une application basée sur ADO.NET. Nous suivons quelques bonnes pratiques simples qui nous permettent d'utiliser le pool de connexion. Par exemple, un bloc de code qui utilise une base de données pourrait ressembler à ceci:Gestion de la connectivité de la base de données avec ADO.NET

using(DbConnection dbConnection = GetDatabaseConnection()) { 
    doWork(); 
} 

FWIW, il n'y a rien de spécial getDatabaseConnection. Il établit une connexion avec la base de données qui est en cours d'exécution MSSQL Server 2000. En fait, il se lit comme suit:

DbConnection GetDatabaseConnection() { 
    return GetConnection(MyConnectionString); 
} 

DbConnection GetConnection(String connectionString) 
{ 
    try { 
     SqlConnection dbConnection = new SqlConnection(connectionString); 
     dbConnection.Open(); 
     return dbConnection; 
    } catch(InvalidOperationException ex) { 
     handleError(ex); 
     throw; 
    } catch(DbException ex) { 
     handleError(ex); 
    } 
} 

En tant que tel, nos connexions sont éliminés à la fin de la portée du bloc. Cependant, nous avons rencontré un petit problème lorsque nous avons commencé à tester l'application. Nous avons trouvé que notre application est très explosive, ce qui signifie qu'il y a des moments où cela devient très bavard et se tait pendant un moment. Le résultat est que nous pouvons avoir plusieurs threads simultanément tout venant pour obtenir une connexion.

Alors imaginez que vous avez 10 discussions. Un lot de travail (ne pas essayer de reformuler le lot de travail) arrive et est segmenté sur quelques threads. Chaque thread tente ensuite d'obtenir une connexion et boom, je suis frappé avec une exception InvalidOperationException. J'ai ajusté le ConnectTimeout et tout ce que cela fait, c'est allonger le temps jusqu'à ce que je reçoive une rafale d'exceptions. Une fois que j'ai passé la phase de «liquidation», l'application est bien. Puis il se repose à nouveau, les connexions "s'en vont" et le processus recommence.

J'ai également essayé de peaufiner le LoadBalanceTimeout, mais les exceptions continuent d'être appliquées. Avez-vous déjà vu ce problème? Des pensées ... Je vais jeter quelques-unes des miennes.

  • Continuellement garder une connexion « chaud »
  • tentative d'ouvrir la connexion à nouveau jusqu'à un certain nombre de tentatives
  • Mettre en oeuvre ma propre connexion mise en commun (bleah, pas intéressé à réinventer la roue)

Modifier:

La plupart des forums que j'ai lus se sont découragés en augmentant la taille du pool de connexion. Par défaut, le pool de connexions a une limite supérieure de 50 connexions (c'est plus que suffisant - si je dois l'augmenter, quelque chose est fondamentalement faux ailleurs). Ce que je remarque est que lorsque le ConnectTimeout est faible, l'exception InvalidOperationException se produit. C'est comme si la mise en route de la connexion était trop longue et les connexions en attente tout le temps d'attente.

MARS est certainement une option ... Le texte de la InvalidOperationException.Message est:

Délai d'attente expiré. Le délai d'expiration s'est écoulé avant l'obtention d'une connexion du pool. Cela peut être dû au fait que toutes les connexions groupées étaient utilisées et que la taille maximale du pool a été atteinte.

+0

Quel est le texte dans .Message (ou .ToString()) de votre InvalidOperationException? –

+1

S'agit-il d'une application winforms ou asp.net? –

+0

Pouvez-vous publier la chaîne de connexion? (De toute évidence XXX sur le nom d'utilisateur/mot de passe et le nom de la base de données pour protéger l'innocent) – BenAlabaster

Répondre

2

Depuis le MSDN (http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx):

Lorsqu'un objet SqlConnection est demandée, elle est obtenue à partir de la piscine si une connexion utilisable est disponible. Pour être utilisable, une connexion doit être inutilisée, avoir un contexte de transaction correspondant ou ne pas être associée à un contexte de transaction, et avoir un lien valide vers le serveur.

Le pooler de connexion satisfait les demandes de connexions en réaffectant les connexions lors de leur relâchement dans le pool. Si la taille maximale du pool a été atteinte et qu'aucune connexion utilisable n'est disponible, la requête est mise en file d'attente. Le pool tente alors de récupérer toutes les connexions jusqu'à ce que le délai d'attente soit atteint (la valeur par défaut est de 15 secondes). Si le pooler ne peut pas satisfaire la demande avant l'expiration de la connexion, une exception est levée .

Traduction: Vérifiez vos contextes de transaction ... si vous avez une taille de pool de 10 connexions, et 10 connexions ont été créées dans différentes transactions, vous êtes foutus. Notez qu'une connexion coupée peut être détectée uniquement après avoir tenté de communiquer avec le serveur. Si une connexion n'est plus connectée au serveur, elle est marquée comme non valide. Les connexions non valides sont supprimées du pool de connexions uniquement lorsqu'elles sont fermées ou récupérées.

S'il existe une connexion à un serveur qui a disparu, cette connexion peut être établie à partir du pool même si le pooler de connexion n'a pas détecté la connexion coupée et l'a marqué comme non valide. C'est le cas parce que le fait de vérifier que la connexion est toujours valide éliminerait les avantages d'avoir un pooler en provoquant un autre aller-retour sur le serveur. Lorsque cela se produit, la première tentative d'utilisation de la connexion détectera que la connexion a été coupée et une exception est levée.

Vous ne pouvez pas vraiment compter sur une connexion pour être connecté? L'article n'explique pas vraiment comment gérer cela ...

Vous pourriez essayer de nettoyer manuellement la piscine de temps en temps en utilisant ClearAllPools et ClearPool, mais cela me semble encore un pansement.

L'article traite également de la sécurité Contextes, en disant:
Après un rôle d'application SQL Server a été activé en appelant le système sp_setapprole procédure stockée, le contexte de sécurité de cette connexion ne peut pas être remis à zéro. Toutefois, si le regroupement est activé, la connexion est renvoyée au pool et une erreur se produit lorsque la connexion regroupée est réutilisée.

Je commence à me demander pourquoi j'utiliser la mise en commun de connexion ...

Et enfin:
Piscine Fragmentation En raison de la sécurité intégrée
Les connexions sont regroupées en fonction de la chaîne de connexion, plus l'utilisateur identité. Par conséquent, si vous utilisez l'authentification de base ou l'authentification Windows sur le site Web et une connexion de sécurité intégrée, vous obtenez un pool par utilisateur. Bien que cela améliore les performances des demandes de base de données suivantes pour un seul utilisateur, cet utilisateur ne peut pas tirer parti des connexions établies par d'autres utilisateurs. Il en résulte également au moins une connexion par utilisateur au serveur de base de données. Par conséquent, si vous utilisez une sécurité intégrée sur une application Web, vous pouvez remplir votre pool de connexions si vous avez suffisamment d'utilisateurs. Sans savoir plus de détails sur votre application, il est difficile de zoomer sur ce qui pourrait vous trébucher, mais j'espère que cela vous donne quelques idées où regarder.

HTH

0

Vous pouvez essayer de paramétrer "Max Pool Size" plus haut. Aussi, vous pouvez essayer d'appeler explicitement "Fermer" sur la connexion.

0

Question 1: Votre méthode GetDatabaseConnection() spin-off un nouveau thread pour générer la connexion de base de données et le retourner au thread principal ... ou sont plusieurs threads essayant d'accéder à celui-ci isntance de la méthode ... ou Cette méthode est-elle une méthode partagée/statique qui récupère simplement une connexion du pool?

Question 2: Quelle marque et quel modèle est votre serveur DB? Serveur SQL? Oracle? PostgreSQL?

Question 3: Avez-vous besoin de tout le travail effectué sur différentes connexions, ou si tout pouvait être fait sur un, cela suffirait-il? Si SQL Server, alors peut-être MARS permettant plusieurs jeux d'enregistrements sur une seule connexion peut aider, mais peut ne pas être réalisable pour votre application.

Question 4: Quel est le détail de l'exception renvoyée?

juste essayer d'obtenir une image claire de la façon dont l'architecture de votre application fonctionne ...

(PS Est-ce que quelqu'un sait comment je FLAG une « réponse » comme « pas une réponse, mais une demande de précisions supplémentaires » ... ie pour cette "réponse")

+0

J'utilise des commentaires dans ces cas. :-) –

+0

Vous pouvez également revenir et éditer cette réponse pour être une vraie réponse lorsque vous aurez votre avis. Donc, cette réponse sans réponse peut devenir une réponse réelle. ;-) – dviljoen

0

Selon MSDN, InvalidOperationException est levée par SqlConnection.Open si vous n'avez pas spécifié une source de données ou un serveur, ou si la connexion est déjà ouverte.

Etes-vous sûr de ne pas avoir d'appels à SqlConnection.Open dans votre méthode "doWork"?

Votre code dans la méthode GetConnection avale également DbException.

+0

Les connexions sont uniquement ouvertes dans la méthode GetConnection(). Nous n'ouvrons jamais de connexions ailleurs. En fait, il échoue la première fois et fonctionne ensuite proprement pendant un certain temps. Sur le code - C'est plus de pseudo code qu'autre chose. Il y a une manipulation réelle dans le code réel, mais je ne voulais pas le copier ici. – Ajaxx

+0

OK mais si vous ne copiez pas le vrai code, il sera plus difficile pour quiconque de trouver le bug ... – Joe