Datenbankzugriffsschicht ohne mit Singletons um sich zu schmeißen?
-
http://www.c-plusplus.net/forum/p2085451#2085451
dot schrieb:
aaaaaaaaaüö schrieb:
Wenn es nur eine DatabaseConnection geben darf, damit DatabaseConnection funktioniert [...]
Warum sollte es nur eine DatabaseConnection geben dürfen damit diese funktioniert, klingt irgendwie nach ziemlicher Frickelei!?
Wenn du mich fragst widerspricht das dem Konzept einer DatabaseConnection mir vorzuschreiben wie oft ich zu welcher Datenbank zu verbinden habe. Eine DatabaseConnection soll konzeptuell gefälligst auch einfach nur das sein: Eine Verbindung zu einer Datenbank. Und wenn meine Anwendung nur eine braucht dann macht sie nur eine und wenn sie mit 10 verschiedenen Datenbanken arbeiten will dann macht sie 10.
Ob es eine oder 10 Datenbanken gibt legt man in Pflichtenheften oder ähnlichem fest. Außerdem hatten wir gerade vorher gesagt, dass es nur eine geben soll und du wolltest die dann lieber überall herrumreichen, statt ein Singleton zu verwenden. Davon bin ich aus gegangen. Wieso sollte das "Überall rumreichen" Design überhaupt irgendwas bringen, wenn man, warum auch immer, plötzlich zwei Datenbanken braucht? Dann musst du überall zwei DatabaseConnections als Parameter einführen, wenn du ein irgendeiner unteren Funktion beide Datenbanken brauchst.
-
Ich habe den Thread nicht verfolgt, aber generell, aus Sicht der derzeitigen SE-Theorie, ist ein Singleton hier falsch. Überall herumzureichen auch. Dafür verwendet man im Normalfall Dependency Injection. Keine Ahnung ob sich das schon bis C++ herumgesprochen hat.
MfG SideWinder
-
Wie funktioniert das eigentlich genau mit Dependency Injection? Ist das Framework, das mir die DatabaseConnection liefern würde auch quasi ein "Singleton" oder wie kommt man dann an seine DatabaseConnection? Kannst du mal ein Codebeispiel zeigen?
-
Ich kann dir nur ein Pseudo-Code-Beispiel liefern, da ich nicht so intensiv mit C++ arbeite. Da es dort keine Reflection gibt muss das sowieso anders ablaufen...am Besten du liest dir mal den Wikipedia Artikel zu DI durch und dort den Abschnitt über Framework-managed DI: http://en.wikipedia.org/wiki/Dependency_injection
Und ja, letzten Endes ist das auch nur ein hübscher Überbau für die set-Methode im anderen Beitrag.
MfG SideWinder
-
Achja bevor ich es vergesse, watch your language. Ich denke volkard wird seine guten Gründe gehabt haben, mag sein, dass sich diese in erster Rage nicht zeigen und von deinem Punkt aus vielleicht auch gar nicht erkennbar sind, aber deswegen muss man nicht gleich um sich schreien
MfG SideWinder
-
Hab ich gerade gelesen, nachdem der deutsche Artikel recht nichtssagen war.
Irgendwie sind die static Methoden jetzt in eine Factory oder ein Framework gewandert, aber da sind sie immer noch, nur heißen nicht mehr getInstance, sondern get("Class"). Wenn man jetzt nur genau eine DatabaseConnection braucht muss das die Factory oder das Framework das verwalten. Wenn man dann zwei will, hat man ziemlich die gleiche Arbeit wie bei einem Singleton.
-
aaaaaaaaaüö schrieb:
Hab ich gerade gelesen, nachdem der deutsche Artikel recht nichtssagen war.
Irgendwie sind die static Methoden jetzt in eine Factory oder ein Framework gewandert, aber da sind sie immer noch, nur heißen nicht mehr getInstance, sondern get("Class"). Wenn man jetzt nur genau eine DatabaseConnection braucht muss das die Factory oder das Framework das verwalten. Wenn man dann zwei will, hat man ziemlich die gleiche Arbeit wie bei einem Singleton.
Eigentlich nicht. Im Falle von Spring (ich musste damit arbeiten, keine Empfehlung meinerseits) bspw. kann ich extern - ohne Änderung am Code - die Anzahl abändern. Also bspw. ob jedes Mal dieselbe DB-Connection injected wird (= Verhalten wie bei Singleton), ob jedes Mal eine neue Connection erzeugt wird (= Verhalten wie bei Klasse) oder sogar ob da ein Pool existiert. Das ist schon sehr mächtig. Natürlich könnte ich das für jeden Typ selbst nachbauen, aber das ist doch stark das Rad neu erfinden, hmm?
Achja ich werde mir die Freiheit nehmen einen Satz aus deinem ersten Posting zu entfernen, es soll ja nett sein hier
Edit: Ich hoffe du siehst das nicht als Zensur an, aber das kann ich so nicht stehen lassen, ok? Den Satz habe ich jedenfalls mal trotzdem archiviert.
MfG SideWinder
-
Das ist jetzt irgendwie im Verlauf verloren gegangen, aber eigentlich ging es nicht mehr um mehrere Connections, was einfach zu ändern ist, sondern um mehrere Datenbanken. Da kann man nicht einfach sagen, ich ändere jetzt mal die Anzahl und dann geht es, sondern muss überall schauen, wo man welche braucht, wenn die Datenbanken für unteschiedliche Daten sind.
-
Naja, das kann ja auch das DI für mich übernehmen. Ich kann ja Parameter mitgeben, bspw. will ich eine DBConn für eine bestimmte Tabelle. Das DI gibt mir dann die richtige DBConn zurück.
Mehrere zu konfigurieren über das DI ist zumindest mit dem Spring Framework mal überhaupt kein Problem.
MfG SideWinder
-
aaaaaaaaaüö schrieb:
Ob es eine oder 10 Datenbanken gibt legt man in Pflichtenheften oder ähnlichem fest.
Es geht aber nicht um Datenbanken sondern um Verbindungen zur Datenbank. Und man kann immer mehr als eine Verbindung aufmachen wenn es denn notwendig ist.
-
SideWinder schrieb:
Naja, das kann ja auch das DI für mich übernehmen. Ich kann ja Parameter mitgeben, bspw. will ich eine DBConn für eine bestimmte Tabelle. Das DI gibt mir dann die richtige DBConn zurück.
Mehrere zu konfigurieren über das DI ist zumindest mit dem Spring Framework mal überhaupt kein Problem.
Ja, aber nur wenn du vorher schon die Arbeit gemacht hast und überall den Tabellennamen angegeben hast, sonst musst du auch wieder alle Stellen entsprechend anpassen.
Shade Of Mine schrieb:
aaaaaaaaaüö schrieb:
Ob es eine oder 10 Datenbanken gibt legt man in Pflichtenheften oder ähnlichem fest.
Es geht aber nicht um Datenbanken sondern um Verbindungen zur Datenbank. Und man kann immer mehr als eine Verbindung aufmachen wenn es denn notwendig ist.
Das man die Verbindungen nicht als Singleton macht hab ich hier schon geschreiben. http://www.c-plusplus.net/forum/p2084799#2084799 Und wenn die Anzahl begrenzt ist brauchst du ein Ding, das mitzählt. dot meinte dann, dass es mehrere Datenbanken geben kann. Warum er das dann wieder DatabaseConnection nannte, war mir nicht ganz klar, aber ich dachte, dass er Datenbanken meint, wahrscheinlich doch nicht.
Im Prinzip läuft es aber doch eigentlich immer auf das gleiche raus, wenn etwas begrenzt ist. Irgendwo hast du ein static das mitzählt. Entweder heißt es
DB.getInstance().getConnection() und die DB ist ein Singleton, hat einen static Zähler und gibt dir die Connection
oder
Framework.get("DB").getConnection(), dann hat das Framework irgendwo ein static Member, dass dir immer diese DB zurück gibt die die Connections zählt.Du hast aber immer einen globalen Zugriff auf die DB und damit auf die Connections und reichst nicht durch die ganze Software die DB oder die Connections rum.
Übrigens ist Dependency Injection ganzschön doppeldeutig. Du injiziert dir damit auch ins ganze Programm Abhängigkeiten zum entsprechenden Framework.
-
SideWinder schrieb:
Ich habe den Thread nicht verfolgt, aber generell, aus Sicht der derzeitigen SE-Theorie, ist ein Singleton hier falsch. Überall herumzureichen auch. Dafür verwendet man im Normalfall Dependency Injection.
Ich hab eigentlich immer DI gemeint. Ich hab nur von "herumreichen" gesprochen weil der Ersteller des ursprünglichen Thread den Begriff verwendet hat. Unter DI versteh ich zumindest dass man Objekten die andere Objekte verwenden Referenzen auf diese übergibt (z.B. im Konstruktor)!? Also z.B. dass ein Objekt das irgendwas mit einer Datenbank tun soll eben im Konstruktor ne Referenz auf die entsprechende Datenbank übergeben bekommt. Genau das hab ich zumindest im andren Thread gepredigt
-
Ja, aber nur wenn du vorher schon die Arbeit gemacht hast und überall den Tabellennamen angegeben hast, sonst musst du auch wieder alle Stellen entsprechend anpassen.
Falls diese Art von Transparenz überhaupt je notwendig ist. Hat man schon den Fall, dass mehrere Datenbanken vorhanden sind weiß man auch meistens welche man haben will, also wohl soetwas:
@Inject(PRODUCTION_DATABASE) DBConn conn; @Inject(BACKUP_DATABASE) // or whatever DBConn conn;
Übrigens ist Dependency Injection ganzschön doppeldeutig. Du injiziert dir damit auch ins ganze Programm Abhängigkeiten zum entsprechenden Framework.
Nein, siehe "non-invasive dependency injection", bspw. das Spring Framework.
Du hast aber immer einen globalen Zugriff auf die DB und damit auf die Connections und reichst nicht durch die ganze Software die DB oder die Connections rum.
Ja, natürlich gibt es irgendwo Zugriff auf die Datenbank. Aber in meinem letzten Projekt fand dieser nur "magically in the background" statt. Ich hatte nirgends diese Zeile von der du da redest
MfG SideWinder
-
Ich kenne mich jetzt nicht so besonders damit aus. Aber wird DI hier jetzt als Lösung für DB dargestellt oder als allgemeine Lösung für alles Mögliche? Ein Framework nutzen zu müssen statt es selbst zu machen ist zwar irgendwo praktisch, bei mir läuten da aber immer die Alarmglocken.
-
Mal noch ne andere Frage. Was soll das eigentlich beim Testen bringen, wenn die DB-Klasse kein Singleton ist? Die DB ansich ist ja sowieso global, also alles was ich in die DB schreibe steht auch im nächsten Testdurchlauf wieder drin, egal ob Singleton oder nicht.
-
aaaaaaaaaüö schrieb:
Die DB ansich ist ja sowieso global, also alles was ich in die DB schreibe steht auch im nächsten Testdurchlauf wieder drin, egal ob Singleton oder nicht.
Ähm nein, du kannst z.B. Ein Mock Objekt statt einer richtigen Datenbank übergeben!?
-
@aaaaaaaaaüö:
Wie willst du z.B. zwei Instanzen eines "Service" im gleichen Prozess laufen lassen, die unterschiedliche Datenbanken verwenden (weil es Instanzen für verschiedene Kunden sind, oder ein Testsystem + ein Stagingsystem etc.), wenn die DB-Connections von einem Singleton verwaltet werden?
-
Eisflamme schrieb:
Ich kenne mich jetzt nicht so besonders damit aus. Aber wird DI hier jetzt als Lösung für DB dargestellt oder als allgemeine Lösung für alles Mögliche?
DI ist eine Lösung für alles Mögliche, auch für deine Datenbank.
-
aaaaaaaaaüö schrieb:
Mal noch ne andere Frage. Was soll das eigentlich beim Testen bringen, wenn die DB-Klasse kein Singleton ist? Die DB ansich ist ja sowieso global, also alles was ich in die DB schreibe steht auch im nächsten Testdurchlauf wieder drin, egal ob Singleton oder nicht.
Abgesehen von Mocking kannst du natürlich die Test-Datenbank vor jedem Testdurchlauf (oder vor jedem Test) auch auf einen Ursprungszustand zurücksetzen.
MfG SideWinder
-
hustbaer schrieb:
@aaaaaaaaaüö:
Wie willst du z.B. zwei Instanzen eines "Service" im gleichen Prozess laufen lassen, die unterschiedliche Datenbanken verwenden (weil es Instanzen für verschiedene Kunden sind, oder ein Testsystem + ein Stagingsystem etc.), wenn die DB-Connections von einem Singleton verwaltet werden?Ich weiß, dass ich mit einem Singleton nicht alles machen kann, aber ich seh überhaupt keinen Vorteil in diesem einmal Erstellen und dann herumreichen, wie es dot erklärt hat, vielleicht hat er es auch falsch erklärt und das hat nichts mit DI zu tun oder ich hab es falsch verstanden oder ich habs verstanden und finde DI schlecht.
Nehmen wir mal an es gibt ein fertiges System das Userdaten (Name, Kontonr.) und alle möglichen anderen Daten in einer DB speichert. Jetzt soll das System aus Sicherheitsgründen so umgebaut werden, dass die Kontonr. in einer anderen Datenbanken gespeichert wird, der Rest kann in der alten DB bleiben. Wenn ich ein Singleton habe kann ich relativ einfach daraus eine Factory mit einem Parameter machen. Der Compiler sagt mir dann wo ich hinschauen muss und ich muss nur den Parameter bei der Singleton/Factroy Verwendung angeben. Wenn ich die DB jetzt immer als Parameter bei Konstruktoren angegeben hab, muss ich jetzt überall da, wo auf die Kontonr. zugegriffen wird, einen zweiten Parameter für die andere DB angeben. Ist das nicht viel hässlicher? Vorallem, gibt es beim herrumreichen, doch auch noch jede Menge "Durchschleifklassen", also Klassen die die DB eigentlich garnicht brauchen, sondern nur an eine andere weitergeben?