Vor einiger Zeit habe ich eine Frage zu TransactionScope gestellt, die zu MSDTC eskaliert, als ich das nicht erwartet habe. ( Vorherige Frage )
In SQL2005 konnten Sie, um ein TransactionScope zu verwenden, nur eine einzelne SqlConnection innerhalb der Lebensdauer des TransactionScopes instanzieren und öffnen. Mit SQL2008 können Sie mehrere SqlConnections instanzieren, aber nur eine einzige kann zu einem bestimmten Zeitpunkt geöffnet sein. SQL2000 wird immer an DTC eskalieren ... wir unterstützen SQL2000 nicht in unserer Anwendung, einer WinForms App, BTW.
Unsere Lösung für das Problem mit nur einer einzigen Verbindung bestand darin, eine TransactionScope-Hilfsklasse namens LocalTransactionScope (alias 'LTS') zu erstellen. Es umschließt ein TransactionScope und, was am wichtigsten ist, erstellt und verwaltet eine einzelne SqlConnection-Instanz für unsere Anwendung. Die gute Nachricht ist, es funktioniert - wir können LTS über verschiedene Code-Teile hinweg verwenden und sie alle schließen sich der Ambient-Transaktion an. Sehr schön. Das Problem ist, dass jede root LTS-Instanz, die erstellt wurde, eine Verbindung aus dem Verbindungspool erstellt und effektiv beendet. Mit 'Effektiv Kill' meine ich, dass es eine SqlConnection instanziiert, die eine neue Verbindung öffnet (aus irgendeinem Grund wird nie eine Verbindung aus dem Pool wiederverwendet) und wenn diese Root-LTS entsorgt wird schließt und entsorgt die SqlConnection, die die Verbindung zurück zum Pool freigeben soll, damit sie wiederverwendet werden kann, jedoch wird sie eindeutig nie wieder verwendet. Der Pool wird aufgebläht, bis er ausgereizt ist, und dann schlägt die Anwendung fehl, wenn eine Verbindung vom Typ + max + + 1 hergestellt wird.
Im Folgenden habe ich eine abgespeckte Version des LTS-Codes und eine Beispiel-Konsolenanwendungsklasse hinzugefügt, die die Erschöpfung des Verbindungspools demonstriert. Verwenden Sie den Aktivitätsmonitor von SQL Server Managment Studio oder die folgende Abfrage, um den aufgeblähten Verbindungspool zu überwachen:
%Vor%Ich verbinde LTS hier und eine Beispiel-Konsolenanwendung, die Sie verwenden können, um für sich selbst zu demonstrieren, dass es Verbindungen aus dem Pool konsumiert und sie nie wieder verwendet oder freigibt. Sie müssen einen Verweis auf System.Transactions.dll hinzufügen, damit LTS kompiliert werden kann.
Zu beachten: Es ist der LTS auf Stammebene, der die SqlConnection öffnet und schließt, die immer eine neue Verbindung im Pool öffnet. Das Verschachteln von LTS-Instanzen macht keinen Unterschied, da nur die Root-LTS-Instanz eine SqlConnection aufbaut. Wie Sie sehen können, ist die Verbindungszeichenfolge immer die gleiche, also sollte die Verbindungen erneut verwenden.
Gibt es eine arkane Bedingung, die wir nicht erfüllen, sodass die Verbindungen nicht wiederverwendet werden? Gibt es dafür eine andere Lösung, als das Pooling komplett auszuschalten?
%Vor%Dies ist ein Program.cs, der die Erschöpfung des Verbindungspools aufzeigt:
%Vor%Das erwartete TransactionScope / SqlConnection-Muster ist laut MSDN :
%Vor%In dem MSDN-Beispiel wird die Verbindung innerhalb des Bereichs bevor der Bereich abgeschlossen ist. Ihr Code ist jedoch anders, er verfügt über die Verbindung nachdem der Bereich abgeschlossen ist. Ich bin kein Experte in Sachen TransactionScope und seiner Interaktion mit der SqlConnection (ich weiß einige Dinge, aber Ihre Frage geht ziemlich tief) und ich kann keine Spezifikationen finden, was das richtige Muster ist. Aber ich würde vorschlagen, dass Sie Ihren Code erneut aufrufen und die Singleton-Verbindung, bevor der äußerste Bereich abgeschlossen ist, ähnlich dem MSDN-Beispiel ablegen.
Außerdem hoffe ich, dass Ihnen klar wird, dass Ihr Code in dem Moment auseinanderfallen wird, in dem ein zweiter Thread in Ihrer Anwendung zum Einsatz kommt.
Tags und Links sql-server c# connection-pooling transactionscope ado.net