6
votes

Piscine de connexion avec des connexions sévères possibles

J'ai plusieurs threads accédant à la même base de données (avec la même chaîne de connexion). Chaque fil:

  • crée sa propre instance SQLConnection à l'aide de la même chaîne de connexion LI>
  • utilise le code ci-dessous pour ouvrir sa propre instance de connexion chaque fois qu'il en a besoin d'un p>

    internal SqlInternalConnection GetOpenConnection()
    {
        SqlInternalConnection innerConnection = this.InnerConnection as SqlInternalConnection;
        if (innerConnection == null)
        {
            throw ADP.ClosedConnectionError();
        }
        return innerConnection;
    }
    


9 commentaires

Pourquoi avez-vous besoin de préserver l'ancien état de connexion? Fermez-le dès que votre prêt avec elle, meilleur via à l'aide de l'instruction . Est-ce quelque chose de statique ici?


@Timschmelter est correct..vous devrait fermer la connexion après l'avoir accédé.


@ Timschmelter: Non, rien de statique; Nous sommes au courant de cette mauvaise pratique, mais c'est le code hérité: il s'agit de la classe de base pour certains objets d'accès de base de données qui prennent en charge l'utilisation de la même connexion à partir de plusieurs objets d'accès à la base de données - moyen: WASOPENCED est utilisé dans la méthode de la classe de base pour laisser la connexion Ouvrir s'il n'était pas ouvert dans la méthode ouverte correspondante - c'est tout.


@Bizapps: S'il vous plaît, jetez un coup d'œil à mon commentaire à Timschmelter et à éditer # 1.


@ Filippopović: J'ai bien peur que vous ayez besoin de ce changement de changement. Jetez un coup d'œil à ma réponse sur une question connexe il y a quelques jours, peut-être que cela aide à comprendre pourquoi il est mauvais pratique de ne pas fermer la connexion: Stackoverflow.com/questions/9705637/... ( J'ai besoin d'aller au lit maintenant)


@ Timschmelter: Merci pour le lien, je suis complètement d'accord avec ça. Juste, je ne vois pas comment cela se rapporte à mon problème - la rupture de changement n'est pas une option pour le moment. La connexion est créée (nouvelle SQLConnection (...)) dans le fil. L'exception n'a pas affiché que quelqu'un d'autre utilise la connexion et SQLConnection.geopEnConnection Le code montre un objet innerconnection coupé. Et je ne sais même pas ce qui définit la nullection intérieure à NULL, mais ne ferme pas, c'est certain que c'est certain parce que c'est la connexion que le pool de connexion ne ferme pas vraiment lorsque vous lui demandez de fermer la connexion.


@ Filippopović: En bref: Ne faites pas de poche sur le territoire de la connexion-piscine;) Modifier : Ils sont liés car je suppose qu'aucune connexion n'est disponible dans la piscine puisque toutes sont utilisées (non fermé de vous).


@ Timschmelter: Bon point, a voté! :) et bonne sommeil, vous n'avez pas de problèmes de piscine de connexion après tout :)


@ Timschmelter: Je suis sûr que je l'ai enfoncé à cause de la fin des blocs avec fermer partout (l'a examiné plusieurs fois jusqu'à présent). Lorsque la piscine de connexion est pleine, l'erreur est "Timetout expirée. La période de délai d'attente écoulée avant d'obtenir une connexion à partir de la piscine. Cela peut avoir eu lieu car toutes les connexions groupées étaient utilisées et la taille maximale de la piscine a été atteinte". Cependant, je reviendrai sur l'état de la piscine de Connection demain et récupérerai ici avec des informations.


3 Réponses :


2
votes

J'ai plusieurs threads accédant à la même base de données (avec la même chaîne de connexion). Chaque fil:

  1. crée sa propre instance SQLConnection à l'aide de la même chaîne de connexion
  2. utilise le code ci-dessous pour ouvrir sa propre instance de connexion chaque fois qu'il en a besoin d'un

    Si vous avez un problème qui apparaît au hasard, dans votre cas, étant donné le code que vous avez affiché, vous pourriez avoir:

    1. Un problème avec la connexion de la connexion sur le serveur
    2. une condition de course quelque part dans votre code

      Tout ce qui étant dit ...

      Vous devez envelopper votre sqlconnection dans un à l'aide de instruction. De cette façon, la connexion sera fermée lorsque votre code, ou le fil, est effectué avec celui-ci. xxx

      de cette façon, la connexion est garantie pour appeler le Disposer () < / Code> Méthode (qui appelle en interne fermer () de toute façon). De cette façon, la connexion peut être retournée à la piscine, si elle est utilisée (ce qu'elle est probablement).


7 commentaires

Je conviens que votre chemin est la voie à suivre en général, mais veuillez fournir une explication supplémentaire sur la manière dont cela se rapporte au problème Innerconnection == Null décrit en question?


@ Filippopović: Pourquoi vérifiez-vous si la connexion est ouverte en premier lieu? Cela suggère que vous n'utilisez pas en utilisant une instruction quelque part dans votre code ...


Aussi, voudriez-vous afficher votre chaîne de connexion et plus de détails sur la base de données?


Eh bien ... c'est un code hérité et chaque méthode a essayé d'ouvrir (comme on le voit en réponse), enfin fermer. Et fermer la connexion de feuilles ouverte s'il a été ouvert lorsque ouvert a été appelé. Simplement pour permettre des instances différentes (non statique) d'utiliser cette même connexion et la même transaction, le cas échéant. En examinant le code, je ne vois aucun moyen de faire sqlconnection.innerConnection pour NULL. Et de sqlconnection.getopenConnection Il est clair qu'il est défini sur NULL d'une manière ou d'une autre. Donc, si c'est ouvert ou non, peu importe. Il échoue sur SQLConnection.Open avec le message Opération non valide. La connexion est fermée.


Et c'est sûr qu'il est fermé, c'est pourquoi je veux l'ouvrir! :)


N'a pas vu votre commentaire sur les informations de base de données au début. Jetez un coup d'œil à la modification n ° 2.


+1 pour le raisonnement et les conseils. Vous pourriez être intéressé de lire ma réponse, aussi.



6
votes

Tout d'abord, lisez-le soigneusement: Piscine de la connexion SQL Server (Ado.net)

Je citerai la partie la plus importante pour vous (je pense):

Un pool de connexion est créé pour chaque chaîne de connexion unique. Lorsqu'un La piscine est créée, plusieurs objets de connexion sont créés et ajoutés à la piscine de sorte que l'exigence minimale de la taille de la piscine soit satisfaite. Les connexions sont ajoutées au pool au besoin, jusqu'à la piscine maximale La taille spécifiée (100 est la valeur par défaut) . Les connexions sont relâchées dans la piscine quand ils sont fermés ou disposés .

Lorsqu'un objet SQLConnection est demandé, il est obtenu à partir du pool. Si une connexion utilisable est disponible. Pour être utilisable, une connexion doit être inutilisé, avoir un contexte de transaction correspondant ou être non apporté à tout contexte de transaction et avoir un lien valide sur le serveur.

Le poolier de connexion satisfait aux demandes de connexions par les connexions de réaffectation car elles sont libérées dans la piscine. si La taille maximale de la piscine a été atteinte et aucune connexion utilisable est Disponible, la demande est mise en file d'attente . Le poolier essaie alors de récupérer tout connexions jusqu'à ce que le délai est atteint (la valeur par défaut est de 15 secondes). Si le poolier ne peut pas satisfaire la demande avant les temps de connexion out, une exception est lancée .

Nous vous recommandons vivement de fermer toujours la connexion lorsque vous sont finis en l'utilisant pour que la connexion soit renvoyée à la bassin. Vous pouvez faire cela en utilisant les méthodes de fermeture ou d'élimination de la Objet de connexion ou en ouvrant toutes les connexions à l'intérieur d'une utilisation Déclaration en C # ou à une déclaration en utilisant Visual Basic. Connexions qui ne sont pas explicitement fermés peuvent ne pas être ajoutés ou retournés à la bassin. Pour plus d'informations, voir Utilisation de l'instruction (référence C #)

en bref : Ne faites pas de poche sur le territoire de la connexion-piscine et fermez les connexions dès que vous avez fini avec eux (Fe via à l'aide de l'instruction ).

depuis Vous ne voulez pas Jetez votre La classe DB dans la poubelle peut , je suggérerais d'augmenter la piscine maximale et / ou du délai d'attente ou de désactiver la mise en commun et de voir ce qui se passe. xxx vous Devrait également essayer d'attraper cette erreur spécifique et Toutes les pools de connexion : xxx

ou consultez ces questions qui semblent prometteuses:


2 commentaires

+1 Pour une réponse très détaillée et beaucoup de bonnes références. Vous pourriez être intéressé de lire ma réponse, aussi.


J'ai oublié de mentionner: j'ai testé le nombre de connexions comme indiqué dans les commentaires de questions, et le nombre de connexions sur le serveur pendant plusieurs exécutions ne dépassait pas 24.



2
votes

réponses fournies par Tim Schmelter et Bryan Crosby est très utile en termes de lignes directrices, de références, de meilleures pratiques et donc. Malheureusement, cela ne me suffisait pas, car je ne peux pas faire de changement de changement de code hérité.

Solution à ce problème particulier était d'encapsuler les méthodes ouvertes et fermées de SQLConnection avec le même verrou. Veuillez noter que cela correspond à notre scénario, cela pourrait ne pas correspondre aux autres.

Je suis vraiment désolé, je ne peux pas creuser de plus en plus et savoir si la source de problème était notre code ou notre pool de connexion n'était pas complètement sûr. Je suis conscient que la source est probablement dans notre code. Ayant cela à l'esprit, cette réponse est plus de contournement que la solution réelle.

Avant que quiconque ne s'applique à cette solution de contournement, veuillez aussi lire d'autres réponses.


0 commentaires