2009-06-29 4 views
8

Wir haben Clientcode, der die SqlConnection-Klasse in .NET verwendet, um mit einer SQLServer-Datenbank zu kommunizieren. Es wird intermittierend mit diesem Fehler Fehler:.NET SqlConnection-Klasse, Verbindungs-Pooling und Reconnection-Logik

„ExecuteReader erfordert eine offene und verfügbare Verbindung Die aktuelle Status der Verbindung ist geschlossen.“

Die „vorübergehende“ Lösung ist, den Prozess neu zu starten, nach dem alles funktioniert - aber das ist offensichtlich unbefriedigend.

Der Code speichert einen Cache für SqlConnection-Instanzen, einen für jede Datenbank.

Wir möchten den Code neu zu schreiben, aber bevor ich das tue, ich brauche ein paar Dinge wissen:

Meine erste Frage ist: Ist es ineffizient wiederholt anschließen und SqlConnection Objekte trennen, oder tut Die zugrunde liegende Bibliothek führt das Verbindungs-Pooling für uns durch?

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

Weil unser Code tut nicht die oben tun, was scheint die wahrscheinliche Ursache des Problems ist, dass etwas auf die zugrunde liegende SQL Server-Datenbank während der „Lebensdauer“ der Verbindung geschieht, die die Verbindung verursacht geschlossen werden ...

Wenn sich herausstellt, dass es sich lohnt, SqlConnection-Objekte zu "cachen", was ist der empfohlene Weg, alle Fehler zu behandeln, die einfach durch "Wiederverbinden" mit der Datenbank gelöst werden können. Ich spreche von Szenarien wie:

  • Die Datenbank offline genommen und wieder online, aber der Client-Prozess hatte keine offene Transaktionen, während dies geschieht
  • Die Datenbank „getrennt“ war, dann „wieder angeschlossen "

Ich bemerke, dass es eine" State "-Eigenschaft auf SqlConnection gibt ... Gibt es eine geeignete Möglichkeit, das abzufragen?

Schließlich habe ich einen Test SQLServer-Instanz mit vollen Zugriffsrechten einrichten: Wie kann ich die genaue Fehler reproduzieren gehen über „ExecuteReader eine offene und verfügbare Verbindung erfordert die aktuellen Status der Verbindung ist geschlossen“

Antwort

19

Nein, Es ist nicht ineffizient, viele SqlConnection Objekte zu erstellen und jedes von ihnen zu schließen, wenn Sie fertig sind. Das ist genau das Richtige. Lassen Sie das .NET Framework Connection Pooling seine Arbeit machen - versuchen Sie es nicht selbst. Sie müssen nichts spezielles tun, um das Verbindungspooling zu aktivieren (obwohl Sie es deaktivieren können, indem Sie in Ihrer Verbindungszeichenfolge Pooling=false setzen).

Es gibt viele Dinge, die schief gehen könnten, wenn Sie versuchen, die Verbindung selbst zwischenzuspeichern. Sag einfach nein :)

+0

Was ich mir erhofft hatte ... Irgendwelche Ideen, wie ich den genauen Fehler, den wir sehen, reproduzieren könnte? (nur um zu "beweisen", dass ich das Problem behoben habe)? –

+0

Schwer zu sagen, um ehrlich zu sein. Es könnte leicht eine Race-Bedingung sein, wenn Sie versuchen, die gleiche Verbindung aus mehreren Threads zu verwenden. –

+1

So deaktivieren Sie das Verbindungs-Pooling: Fügen Sie "Pooling = False" hinzu. zu der Verbindungszeichenfolge. – Richard

2

Sie sollten connection pooling auf Ihrer Verbindungszeichenfolge aktivieren. In diesem Fall fügt die Laufzeitumgebung Ihre Verbindungen zum "Pool" hinzu, wenn Sie sie schließen, anstatt wirklich zu disconnecting. Wenn eine 'neue' Verbindung aus dem Pool genommen wird, wird sie zurückgesetzt (dh sp_reset_connection wird aufgerufen) und dann Ihrer Anwendung als brandneue, frische Verbindung präsentiert. Der Pool behandelt solche Fälle transparent, als ob die Verbindung im Leerlauf im Pool geschlossen wäre.

Die Kosten für die Erstellung einer neuen Verbindung "von Grund auf" sind von Bedeutung, da die Authentifizierung mehrere Roundtrips zwischen Client und Server erfordert (je nach Authentifizierungsmethode und SSL-Einstellungen kann es im besten Fall 1 Roundtrip im Vergleich zu etwa 10 Zoll sein) schlechter).

Und um Ihre Frage zu beantworten, erhöhen Verbindung das OnStateChange Ereignis, wenn ihr Zustand sich ändert, aber Sie sollten sich nicht darum kümmern, wenn Sie das Pooling verwenden.

+0

Verbindungspooling ist die Standardeinstellung, Sie müssen nichts tun, um sie zu aktivieren. Sie können es deaktivieren, aber sie sind eine seltene Anforderung. – Richard

+1

Wenn Sie das Verbindungspooling aktiviert haben und eine Verbindung öffnen, um zu prüfen, ob eine Datenbank vorhanden ist, müssen Sie darauf achten, dass die Datenbank basierend auf diesen Informationen erstellt wird. Dann können Sie mit dem sp_reset_connection-Trick die Datenbank nicht sehen. Also die erste Verbindung ohne Verbindungspooling. –

1

In meiner letzten Erfahrung, wenn Sie diesen Code verwenden:

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

einen Fehler hat, und schließen Sie nicht explizit die Verbindung, wird es nicht wieder in den Pool geschlossen oder überprüft werden. Also nutze einen catch oder finally block um die Verbindung zu schließen