Datenbankzugriffsschicht ohne mit Singletons um sich zu schmeißen?
-
Die Idee, Tabellen der DB auf Tabellenobjekte abzubilden, ist meiner Meinung nach ziemlicher Blödsinn. JDBC/ODBC kennen ein Recordset, das eben die Ergebnismenge einer SQL-Abfrage enthält. Ich kann aber keinen Sinn darin sehen, dieses Recordset global zugreifbar zu machen.
Man könnte die SQL-Anweisung global machen, um bei einer Abfrage nur noch die Bindevariablen setzen zu müssen. Man spart sich das Parsen auf der Datenbankseite, die Abfrage kann also insgesamt schneller ausgeführt werden. Moderne Datenbanksysteme enthalten aber ihrerseits Cachingmechanismen für Abfragen, sodass der Vorteil eher marginal ist.
Als einziges sinnvolles globales Objekt bleibt die Connection, die man dann sicher als Singelton ausführen könnte.
-
manni66 schrieb:
Als einziges sinnvolles globales Objekt bleibt die Connection, die man dann sicher als Singelton ausführen könnte.
Was ich nicht tun würde. Wer sagt dass es nur eine Connection geben darf!?
-
-
dot schrieb:
manni66 schrieb:
Als einziges sinnvolles globales Objekt bleibt die Connection, die man dann sicher als Singelton ausführen könnte.
Was ich nicht tun würde. Wer sagt dass es nur eine Connection geben darf!?
Das hängt von der Anwendung ab. Wenn sie mehrere Connections benötigt, funktioniert es eben nicht. Benötigt sie nur eine oder eine fest vorgegebene Anzahl, kann man es mit einem Singleton lösen, man muss aber nicht. Benötigt man viele verschiedene Connections, so kann man einen Connection Pool verwenden, der letzten Endes wieder eine globale Verwaltung darstellt.
-
Es gibt einen wesentlichen Unterschied zwischen benötigt nur eine und es darf bis ans Ende aller Tage um keinen Preis der Welt jemals mehr als eine geben. Singleton ist für letzteres gedacht
-
dot schrieb:
Es gibt einen wesentlichen Unterschied zwischen benötigt nur eine und es darf bis ans Ende aller Tage um keinen Preis der Welt jemals mehr als eine geben. Singleton ist für letzteres gedacht
Du weißt aber schon, dass man seinen Code auch ändern kann, wenn sich die Anforderungen ändern
-
...und genau dann offenbart sich das große Problem mit Singleton
-
dot schrieb:
...und genau dann offenbart sich das große Problem mit Singleton
Welches?
-
Du musst nun sämtlichen Code anfassen der den "Singleton" verwendet und den "Singleton" rausfactoren und durch ne Referenz ersetzen. Da der "Singleton" ja so einfach von überall aus erreichbar ist ist das vermutlich sehr viel Code da du dir beim Schreiben des Codes mit "Singleton" nicht viele Gedanken darüber gemacht hast was, wann, wie, wo wirklich Zugriff auf welche Schnittstelle braucht (99.99% aller "Singletons" werden ja von vornherein von faulen Programmierern verwendet um sich genau keine Gedanken machen zu müssen). Dein Code ist also an allen Ecken und Enden übersäht mit Zugriffen auf den "Singleton" und das so gewachsene Design vermutlich an einigen Stellen gar nicht wirklich für eine ordentlichen Lösung über Dependency Injection geeignet. D.h. den Singleton loszuwerden bedeutet ein komplettes redesign großer Teile des Systems. Wenn du es stattdessen einfach von vornherein so gebaut hättest dass Objekte die Objekte benötigen diese über entsprechende Referenzen explizit kennen wäre das einzige was du nun tun müsstest einfach eine zweite Datenbankverbindung zu instanzieren, den entsprechenden Objekten das andere Datenbankverbindungsobjekt zu reichen und das wars.
Ich muss dazu sagen dass ich selber wenig Erfahrung mit dem Problem habe da ich Singleton schon immer rein gefühlsmäßig aus dem Weg gegangen bin, noch bevor ich eigentlich genau wusste warum. Ein paar Mal habe ich aber auch mit dem Gedanken gespielt einen Singleton einzusetzen und ich war noch jedesmal später froh es nicht getan zu haben da es jedesmal später im Projekt genau zu diesem Problem gekommen wär. Natürlich könnte man sagen ich hatte einfach Pech. Aber wir hatten auf der Uni auch mal eine lustige Dikussion über genau dieses Problem und ich kann dir sagen dass da in einer Gruppe von 10 Leuten mindestens 5 dabei waren deren Erzählungen genau so begonnen haben: "Wir hatten da mal eine Datenbankverbindung...""Singletons" sind wie Krebs. Wenn du merkst dass du sie hast ist es meist zu spät, sie haben schon überall in deinen Code metastasiert...
-
dot schrieb:
Du musst nun sämtlichen Code anfassen der den "Singleton" verwendet und den "Singleton" rausfactoren und durch ne Referenz ersetzen. Da der "Singleton" ja so einfach von überall aus erreichbar ist ist das vermutlich sehr viel Code da du dir beim Schreiben des Codes mit "Singleton" nicht viele Gedanken darüber gemacht hast was, wann, wie, wo wirklich Zugriff auf welche Schnittstelle braucht (99.99% aller "Singletons" werden ja von vornherein von faulen Programmierern verwendet um sich genau keine Gedanken machen zu müssen). Dein Code ist also an allen Ecken und Enden übersäht mit Zugriffen auf den "Singleton" und das so gewachsene Design vermutlich an einigen Stellen gar nicht wirklich für eine ordentlichen Lösung über Dependency Injection geeignet. D.h. den Singleton loszuwerden bedeutet ein komplettes redesign großer Teile des Systems. Wenn du es stattdessen einfach von vornherein so gebaut hättest dass Objekte die Objekte benötigen diese über entsprechende Referenzen explizit kennen wäre das einzige was du nun tun müsstest einfach eine zweite Datenbankverbindung zu instanzieren, den entsprechenden Objekten das andere Datenbankverbindungsobjekt zu reichen und das wars.
Ehrlich gesagt weiß ich nicht wieso das besser sein sollte. Woher weißt du jetzt welches Objekt welche Datenbankverbindung bekommen soll und wieviel Connections du schon hast? Wahrscheinlich brauchst du ein Singleton, das mitzählt. Die Connection sollte man aber innerhalb von Transaktionen rumreichen und nicht überall das Singleton verwenden.
-
aaaaaaaaaüö schrieb:
Woher weißt du jetzt welches Objekt welche Datenbankverbindung bekommen soll und wieviel Connections du schon hast?
Wenn du das nicht weißt ist doch sowieso alles sinnlos?
aaaaaaaaaüö schrieb:
Wahrscheinlich brauchst du ein Singleton, das mitzählt.
wofür?
aaaaaaaaaüö schrieb:
Die Connection sollte man aber innerhalb von Transaktionen rumreichen und nicht überall das Singleton verwenden.
Wenn du das tust dann hast du das Problem natürlich nichtmehr. Das ist aber eben genau nicht wie 99.99% aller "Singletons" da draußen verwendet werden...
-
dot schrieb:
aaaaaaaaaüö schrieb:
Woher weißt du jetzt welches Objekt welche Datenbankverbindung bekommen soll und wieviel Connections du schon hast?
Wenn du das nicht weißt ist doch sowieso alles sinnlos?
aaaaaaaaaüö schrieb:
Wahrscheinlich brauchst du ein Singleton, das mitzählt.
wofür?
Ich geh mal davon aus, dass man mit mehreren Threads arbeitet und nicht jeder Thread für immer eine Connection offen halten kann, also die Anzahl der Connections begrenzt ist, sonst ist es relativ simpel. Dann kannst du wirklich alle Connections beim Programmstart verteilen und rumreichen.
-
Und wo genau profitiert man in diesem Szenario von Singleton? Und wer sagt dass alle Connections überhaupt zur selben Datenbank laufen?
-
Wenn du 100 Threads hast und nur 10 Connections, kannst du immer 10 Threads die gleiche Connection geben und die anderen 9 dann warten lassen solange ein Thread die Connection verwendet. Oder du hast ein Singleton, dass die 10 Connections verwaltet und eine an den Thread gibt der gerade eine braucht. Dann müssen die Threads erst warten wenn alle Connections verwendet werden und nicht wenn einer zufällig gerade die gleiche braucht.
-
Ja, aber das hat doch absolut nichts mit dem Singleton Pattern zu tun!? Die entsprechende Funktionalität würd ich hinter einem DatabaseConnection Objekt kapseln das ich einfach weiterreiche an wen auch immer es braucht. Ich seh jedenfalls wirklich nicht wo genau man da jetzt den Singleton Pattern brauchen sollte!?
-
Na, du kannst natürlich immer statt eines Singletons ein einziges Objekt erzeugen und das dann überall rumreichen. Wenn du dann noch ein paar mehr solcher Objekte hast, hast du überall x Parameter mehr in deinen Methoden und Konstruktoren, da würde ich dann doch irgendwann ein Singleton nehmen. Man muss ja nicht für alle theoretischen Fälle ein Design vorsehen. Mehrere Datenbanken wird wahrscheinlich nicht mal 0.1% aller Anwendungen brauchen.
-
aaaaaaaaaüö schrieb:
Wenn du dann noch ein paar mehr solcher Objekte hast, hast du überall x Parameter mehr in deinen Methoden und Konstruktoren [...]
Meiner Erfahrung nach ist das nicht so schlimm. Wenn es viele sind ist das nur ein Zeichen dass am Design grundsätzlich was nicht stimmt.
aaaaaaaaaüö schrieb:
Man muss ja nicht für alle theoretischen Fälle ein Design vorsehen. Mehrere Datenbanken wird wahrscheinlich nicht mal 0.1% aller Anwendungen brauchen.
Gut. Aber ich seh keinen Grund diese 0.1% auszuschließen wenn mir das keinen Vorteil bringt!? Design und Implementierung werden durch ein Singleton jedenfalls sicherlich nicht einfacher. Das Singleton bringt nämlich einige nichttriviale Konsequenzen mit sich. Z.B. Initialisierungsreihenfolge, Multithreading (getInstance() gegen Race Condition absichern), Unit-Testing (globaler statischer Zustand), ...
-
Wie groß sind eigentlich die Teams in denen du programmierst? Wie stellst du sicher, das jeder die "einzelnen" Objekte übergibt und nicht selber falsch erstellt?
-
aaaaaaaaaüö schrieb:
Wie groß sind eigentlich die Teams in denen du programmierst?
Ich hab bisher noch nie wirklich in größeren Teams gearbeitet, maximal 4 Leute.
aaaaaaaaaüö schrieb:
Wie stellst du sicher, das jeder die "einzelnen" Objekte übergibt und nicht selber falsch erstellt?
Das System zwingt einen doch schon dazu!? Ohne ein Objekt zu übergeben lassen sich die andren Objekte garnicht instanzieren. Ich seh da kein Problem, aber du wirst mir sicher gleich sagen dass mir einfach die Erfahrung fehlt worauf ich natürlich nichts entgegnen kann. Die potentielle Unfähigkeit meiner Teamkollegen ist für mich jedenfalls kein Argument für ein Singleton und ich wüsste nicht was passieren müsste dass sich daran was ändert.
-
Ist auch etwas seltsam steigende Komplexität (mehrere Objekte die rumgereicht werden müssen), als Argument für Singletons/globale Variablen anzuführen.
Mal ganz abgesehen davon, dass man mehrere Objekte zu einem zusammenfassen kann, wenn sie öfters zusammen gebraucht werden. Soll angeblich manchmal ganz gut funktionieren.