Wir haben ein System, bei dem die Datenbankverbindung einmal mit einer gemeinsamen Methode hergestellt und in der jeweiligen zu verwendenden Klasse übergeben wird. Es gibt Zweifel, dass das Übergeben der Datenbankverbindung als Parameter an verschiedene Klassen zu Problemen führen würde. Daher überprüfe ich hier, ob dies tatsächlich möglich ist, und gibt es dafür bessere Muster?
Ich weiß, dass es einige ORM-Tools gibt, um die Persistenz zu gewährleisten, aber darauf können wir noch nicht eingehen.
Jedes Feedback ist willkommen, danke.
java
database
patterns-and-practices
ipohfly
quelle
quelle
Antworten:
Ja, es ist sicher, eine Verbindung weiterzugeben. Sie behandeln die Verbindung in einem äußeren Steuerblock. Daran ist nichts Unsicheres.
Was unsicher ist, ist das Schreiben von Code, der nicht garantiert, dass die Verbindung rechtzeitig ordnungsgemäß entsorgt wird. Das Vergessen, eine Ressource zu bereinigen, hat nichts mit dem Weitergeben zu tun. Sie können genauso gut Code schreiben, der eine hängende Verbindung hinterlässt, ohne sie irgendwo weiterzugeben.
In C ++ sind Sie durch RAII geschützt, wenn Sie auf dem Stapel zuweisen oder intelligente Zeiger verwenden. Machen Sie in C # eine harte Regel, dass alle verfügbaren Objekte (wie Verbindungen) in einem "using" -Block deklariert werden. In Java mit Try-finally-Logik aufräumen. Führen Sie Codeüberprüfungen für alle Datenschichtcodes durch, um dies sicherzustellen.
Der häufigste Anwendungsfall ist, wenn Sie mehrere Operationen haben, die in vielen Permutationen kombiniert werden können. Und jede dieser Permutationen muss eine Atomtransaktion sein (alle erfolgreich oder Rollback). Dann müssen Sie die Transaktion (und damit die entsprechende Verbindung) an alle Methoden weitergeben.
Angenommen, wir haben viele foobar () -Aktionen, die auf verschiedene Arten als Atomtransaktionen kombiniert werden können.
Übrigens möchten Sie Verbindungen so spät wie möglich öffnen und sie so schnell wie möglich entsorgen. Ihre Teamkollegen könnten Recht haben, wenn Sie Verbindungen als Objektmitglieder behandeln, sie als unnötigen Status einführen und Verbindungen viel länger als nötig offen lassen. Das Übergeben einer Verbindung oder Transaktion als Parameter ist jedoch nicht von Natur aus falsch.
Übrigens. Abhängig von der Unterstützung Ihrer Sprache für erstklassige Funktionen können Sie eine Liste von foobar () - Aktionen ausführen. Eine Funktion könnte also alle Permutationen der Aktionen verarbeiten. Eliminieren der Duplizierung des äußeren Steuerblocks für jede Permutation.
quelle
Es hört sich so an, als wären Sie hinter der Abhängigkeitsinjektion her . Das heißt, die gepoolte Verbindung wird einmal erstellt und dort eingefügt, wo sie benötigt wird. Das Übergeben der Verbindung über einen Methodenparameter ist sicherlich eine Möglichkeit, Abhängigkeiten zu injizieren, aber ein IoC-Container wie Guice, PicoContainer oder Spring ist eine andere (sicherere) Möglichkeit, dies zu tun.
Mit DI können Sie die Logik rund um das Erstellen, Öffnen, Verwenden und Schließen der Verbindung ordentlich zusammenfassen - weg von Ihrer Kerngeschäftslogik.
Spring JDBC et al. Sind weitere Beispiele für die Durchführung dieser Art von Verhalten für Sie
quelle
Das Weitergeben von Datenbank-Dingen anstelle von Daten-Dingen kann zu Problemen führen. Insofern, wann immer es praktikabel ist, übergeben Sie keine Datenbanksache, es sei denn, Sie können eine ordnungsgemäße Datenbankhygiene gewährleisten.
Das Problem beim Weitergeben von Datenbank-Dingen ist, dass es schlampig sein kann. Ich habe mehr als einen Fehler im Code mit jemandem gesehen, der eine Datenbankverbindung herumgereicht hat, dass jemand dann eine Ergebnismenge aufnimmt und in einem lokalen Objekt (der Ergebnismenge, die noch mit der Datenbank verbunden ist) versteckt und dann einen Cursor in der Datenbank für eine bedeutende Zeit. In einer anderen Instanz hat jemand eine Ergebnismenge an eine andere Person übergeben (die dann gespeichert wurde), und die Methode, die die Ergebnismenge übergeben hat, hat sie (und die Anweisung) geschlossen, was zu Fehlern führte, wenn andere Methoden versuchten, mit der Ergebnismenge zu arbeiten, die nicht mehr vorhanden war.
All dies ist darauf zurückzuführen, dass die Datenbank, die Verbindung, die Anweisung, die Ergebnismenge und ihre Lebenszyklen nicht berücksichtigt werden.
Um dies zu vermeiden, gibt es vorhandene Muster und Strukturen, die besser mit Datenbanken spielen und keine Datenbank haben, die aus den Klassen, in denen sie beschränkt sind, herauskommen muss. Daten gehen ein, Daten gehen aus, die Datenbank bleibt erhalten.
quelle
Root
ein Dao zu erhalten. Aber dann merkt man, dass man auch einen Weg haben will,Node
ohne das ganzeRoot
Objekt damit herauszuziehen . Wie lässt sich dasRoot
Dao denNode
Dao-Code aufrufen (dh wiederverwenden), aber sicherstellen, dass dasNode
Dao die Verbindung nur schließt, wenn dasNode
Dao direkt aufgerufen wird, und die Verbindung offen hält, wenn dasRoot
Dao aufgerufen wird?Das Weitergeben von
Connection
Instanzen ist normalerweise kein Problem, obwohl in den meisten Situationen nur die DAO-Implementierungen etwas damit zu tun haben sollten. Da Ihr Problem darin besteht, dass Verbindungen nach der Verwendung nicht geschlossen werden, ist es tatsächlich einfach zu beheben: DasConnection
Objekt muss auf derselben Ebene geschlossen werden, auf der es geöffnet ist, dh auf dieselbe Weise. Ich persönlich verwende das folgende Codemuster:Auf diese Weise stelle ich sicher, dass alle Verbindungen immer geschlossen sind, auch wenn eine Ausnahme innerhalb des Blocks ausgelöst wird. Ich gehe tatsächlich so lange, wie ich genau das gleiche Muster für
Statement
undResultSet
Instanzen verwende, und alles war bisher reibungslos.Bearbeiten 2018-03-29: Wie von user1156544 in den Kommentaren unten angegeben, sollte ab Java 7 die Verwendung des Try-with-Resources-Konstrukts bevorzugt werden. Mit ihm kann das Codemuster, das ich in meiner ersten Antwort angegeben habe, folgendermaßen vereinfacht werden:
quelle
dataSource
eher benennen sollen alsDataSource
(ich werde meine Antwort in Bezug auf diesen Punkt korrigieren ). Der genaue Typ dieses Objekts wärejavax.sql.DataSource
. In altem Code hatte ich früher einen Singleton, der alle verfügbaren Datenquellen in meinen Anwendungen verwaltete. Meine DAOs mussten dies nicht durch wissen, da dieDataSource
Instanz durch Abhängigkeitsinjektion bereitgestellt wird.Es ist ein Kompromiss, Dinge auf diese Weise zu tun, anstatt einen Singleton zu verwenden, den Sie nach Bedarf erhalten können. Ich habe in der Vergangenheit Dinge in beide Richtungen getan.
Im Allgemeinen müssen Sie über die Konsequenzen der Datenbankverbindungsverwaltung nachdenken. Dies kann orthogonal zur Verwendung von Datenbankabfragen sein oder auch nicht. Wenn Sie beispielsweise eine Datenbankverbindung für eine bestimmte Anwendungsinstanz haben und diese geschlossen wird, wenn sie nicht verwendet wird, ist dies orthogonal. Stellen Sie das Management in eine Singleton-Klasse und geben Sie es nicht weiter. Auf diese Weise können Sie die Datenbankverbindung nach Bedarf verwalten. Wenn Sie beispielsweise bei jedem Commit eine Verbindung schließen (und beim nächsten Aufruf erneut öffnen) möchten, ist dies bei einem Singleton einfacher, da die API dafür zentralisiert werden kann.
Angenommen, Sie müssen einen Verbindungspool verwalten, bei dem ein bestimmter Anruf möglicherweise eine beliebige Verbindung verwenden muss. Dies kann beispielsweise bei verteilten Transaktionen auf mehreren Servern der Fall sein. In diesem Fall ist es normalerweise weitaus besser, das Datenbankverbindungsobjekt zu übergeben, als mit Singletons zu arbeiten. Ich denke, dies ist normalerweise der seltenere Fall, aber es ist nichts Falsches daran, es zu tun, wenn Sie es brauchen.
quelle