Verständnisfrage zu Dispose, using, Referenzen in C# und der Klasse SqlConnection.
-
Optimizer schrieb:
Irgendwie baust du selber einen Connection-Pool, obwohl es das fertig gibt. Anscheinend hast du nicht die Anforderung, dass eine Aufgabe die Verbindung braucht, die eine bestimmte "Vorgänger"-Aufgabe schon verwendet hat. Also würde ich für jede Aufgabe eine neue Connection erstellen (und disposen) und vom Framework poolen lassen.
Das Problem das ich an der Sache sehe ist eben, dass ich dann zeitweise x Verbindungen GLEICHZEITIG offen habe, d.h. der Connection-Pool greift hier ja überhaupt garnicht.
Optimizer schrieb:
Wenn du es dennoch so machen willst, solltest du verhindern, dass man ein dispostes Objekt wieder verwendet. Das hilft, frühzeitig Fehler zu erkennen und der Test kostet minimal (und verglichen mit einem Datenbankzugriff gar nichts).
Das verstehe ich nicht. Was habe ich übersehen/vergessen?
-
dEUs schrieb:
Das Problem das ich an der Sache sehe ist eben, dass ich dann zeitweise x Verbindungen GLEICHZEITIG offen habe, d.h. der Connection-Pool greift hier ja überhaupt garnicht.
Was heißt gleichzeitig? Hast du hundert Threads, die gleichzeitig was committen? Wenn ja, was bringt es, das alles über eine Verbindung zu machen, anstatt über hundert? Wenn nein, sieht es dann so aus:
using( ... ) {
}
using( ... ) {
}
using( ... ) {
}
using( ... ) {
}
using( ... ) {
}Also wird die Verbindung immer wieder dem Pool zugeführt. Wenn du tatsächlich viel gleichzeitig machst, was genau soll deinen selbstgemachten Pool schneller machen als den fertigen?
Oder hast du sowas:
using( ... ) {
using( ... ) {
using( ... ) {
}
}
}Sowas hab ich auch. Ich habe mehrere Service-Klassen, deren Methoden per Remoting aufgerufen werden und sich auch gegenseitig benutzen. Die Connection die von allen Methoden verwendet wird ist ein Member der Service-Klasse und wird vom Connection-Pool verwaltet.
Die Methoden nehmen keine Connection (auch keine selbstgebaute) und erstellen auch keine. Die Connection wird bei der Konstruktion der Service-Klasse gebaut und lebt genau 5min. Sowas wie Connections gibt es nach außen nicht, nur data sets.dEUs schrieb:
Das verstehe ich nicht. Was habe ich übersehen/vergessen?
Folgendes ist möglich und sollte nicht sein:
DBConnection con = new DBConnection(); con.Dispose(); irgendwas = con.Connection; // gar nichts sollte hier mehr gehen
-
Optimizer schrieb:
dEUs schrieb:
Das Problem das ich an der Sache sehe ist eben, dass ich dann zeitweise x Verbindungen GLEICHZEITIG offen habe, d.h. der Connection-Pool greift hier ja überhaupt garnicht.
Was heißt gleichzeitig? Hast du hundert Threads, die gleichzeitig was committen? Wenn ja, was bringt es, das alles über eine Verbindung zu machen, anstatt über hundert? Wenn nein, sieht es dann so aus:
using( ... ) {
}
using( ... ) {
}
using( ... ) {
}
using( ... ) {
}
using( ... ) {
}Also wird die Verbindung immer wieder dem Pool zugeführt. Wenn du tatsächlich viel gleichzeitig machst
Sowas habe ich nciht, nein.
Optimizer schrieb:
was genau soll deinen selbstgemachten Pool schneller machen als den fertigen?
Meine Klasse stellt keinen Pool dar. Meine Klasse stellt sicher, dass alle exakt ein und die selbe Verbindung verwenden.
Optimizer schrieb:
Oder hast du sowas:
using( ... ) {
using( ... ) {
using( ... ) {
}
}
}Ja. Aber halt nicht in einer Funktion, sondern in einer Hauptfunktion die wiederum kleinere Funktionen aufruft die auch DB-Arbeit leisten.
Optimizer schrieb:
Sowas hab ich auch. Ich habe mehrere Service-Klassen, deren Methoden per Remoting aufgerufen werden und sich auch gegenseitig benutzen. Die Connection die von allen Methoden verwendet wird ist ein Member der Service-Klasse und wird vom Connection-Pool verwaltet.
Die Methoden nehmen keine Connection (auch keine selbstgebaute) und erstellen auch keine. Die Connection wird bei der Konstruktion der Service-Klasse gebaut und lebt genau 5min. Sowas wie Connections gibt es nach außen nicht, nur data sets.Und was ist da der Vorteil zu meiner Methode in der die Verbindung nicht 5 Minuten lebt, sondern immer nur so lang wie benötigt?
Optimizer schrieb:
dEUs schrieb:
Das verstehe ich nicht. Was habe ich übersehen/vergessen?
Folgendes ist möglich und sollte nicht sein:
DBConnection con = new DBConnection(); con.Dispose(); irgendwas = con.Connection; // gar nichts sollte hier mehr gehen
Ich setze mit Dispose das delete in C++ gleich. D.h. dein Aufruf nach dem Dispose wäre im Grunde einfach falsch. Ist dem nicht so?
als Disclaimer ;):
Ich bin neu in der Datenbank-Programmierung...
-
dEUs schrieb:
Und was ist da der Vorteil zu meiner Methode in der die Verbindung nicht 5 Minuten lebt, sondern immer nur so lang wie benötigt?
Was heißt schon so lange wie benötigt? In der Praxis treten Datenbankzugriffe oft sehr gehäuft auf und dann wieder eine Stunde lang nichts. Das automatische Schließen nach einer bestimmten Zeit ist eingebaut, ich habe nichts dafür machen müssen und ich habe es deshalb verwendet und mir nicht den Kopf zerbrochen. Ich denke auch, dass es Performance-mäßig recht ideal ist und wir haben generell eher woanders Performance-Probleme.
Aber jetzt verstehe ich zumindest deinen Anwendungsfall. Wenn du deine Klasse dafür geeignet findest, spricht natürlich nichts dagegen, sie herzunehmen. Das mit dem Pool kam daher, dass ich deinen Anwendungsfall falsch verstanden habe.
Ich setze mit Dispose das delete in C++ gleich. D.h. dein Aufruf nach dem Dispose wäre im Grunde einfach falsch. Ist dem nicht so?
Der Aufruf wäre falsch, ja. Was auch falsch ist, davon auszugehen, dass andere oder man selber alles richtig macht. Dein dispostes Objekt zu benutzen führt zu undefiniertem Verhalten, weil je nach Umstände verschiedene Dinge passieren (alles wird geil gemacht, eine Exception kommt, nichts kommt aber nichts wird gemacht, ...). Undefiniertes Verhalten ist grundsätzlich ein Risiko für die Sicherheit und sowas will man in .Net-Klassen nicht haben. Falscher Index, falscher Parameter, falsche Verwendung zur falschen Zeit, alles abfangen. Die Philosophie ist hier gänzlich anders. Man geht nicht davon aus, dass der Benutzer einer Klasse ein Mensch ohne Fehler ist. Das heißt nicht, dass man falsche Benutzung toleriert. Fatal wäre es zu prüfen, ob die Verbindung noch offen ist und wenn nicht, einfach die Operation nicht ausführen. Das würde nicht zu einer Exception führen, aber würde Fehler verbergen. Deshalb sollte man eine hier ObjectDisposedException werfen, um die falsche Benutzung anzuzeigen und nicht zu tolerieren.
Speziell zum disposen gibt es Guidelines, von denen zwei der wichtigsten du verletzt:
- erlaube, Dispose() mehrmals aufzurufen
- erlaube nicht, ein dispostes Objekt zu verwendenAndere Bibliotheken, Tools und Programmierer verlassen sich darauf, dass du das Dispose-Pattern korrekt implementierst. Siehe dazu:
http://msdn2.microsoft.com/en-us/library/fs2xkftw.aspx