Noch einfacherer Java / SQL-datatransfer benötigt

Also benutze ich jdbc, um mit einer MySQL DB zu sprechen. Für viele Tabellen und viele Abfragen / Views habe ich eine class erstellt, die eine Zeile der Tabelle oder das Abfrage / Tabellen-Ergebnis kapselt. Zugriffe auf die DB geben ein object einer solchen class (wenn ich genau weiß, dass es nur eine passende Zeile gibt) oder einen Vektor solcher objecte zurück.

Jede class verfügt über eine Factory-Methode, mit der ein object aus einer Zeile eines ResultSets erstellt wird. Viele ResultSet.getXXX () – methods werden benötigt, genau wie die genaue Buchhaltung darüber, welcher Wert sich in welcher Spalte befindet, insbesondere nach Änderungen am Tabellen- / Abfrage- / viewslayout.

Das Erstellen und Pflegen dieser objecte ist eine langweilige, arbeitsintensive und verwirrende Aufgabe. Mit anderen Worten, die Art der Aufgabe, die von einem Werkzeug ausgeführt wird. Es sollte SQL (die MySQL-Variante, leider) lesen und Java-Code generieren. Oder geben Sie mir wenigstens eine Repräsentation (XML? DOM?) Der Tabelle / Abfrage / view, die es mir ermöglicht, die Java-Code-Generation selbst zu machen.

Können Sie dieses Werkzeug benennen?

Solutions Collecting From Web of "Noch einfacherer Java / SQL-datatransfer benötigt"

Wenn Sie nach einem einfachen Rahmen suchen, um mit der Arbeit im Schreiben sql zu helfen, würde ich empfehlen, ibatis sql maps . Dieser Rahmen tut im Grunde genau das, was Sie wollen.

Hibernate ist auch eine gute Option, aber es scheint ein bisschen überdimensioniert für ein einfaches Problem wie Ihres.

Vielleicht sehen Sie sich auch den Federrahmen an. Dies zielt darauf ab, eine einfache Umgebung zum Schreiben von Java-Anwendungen zu schaffen und hat auch eine sehr brauchbare SQL-Abstraktion. Aber sei vorsichtig mit dem Frühling, du könntest den Rahmen mögen und zu viele glückliche Stunden damit verbringen 8)

Was deine Sorge mit der reflection betrifft. Java hat keine größeren Probleme mehr mit Performance Overhead der Reflektion (zumindest seit Version 1.4 und mit O / R Mapping Tools).

Meiner Erfahrung nach ist es besser, sich um gut geschriebenen und leicht verständlichen Code zu kümmern, als sich um etwas Performance-Overhead zu kümmern, das vielleicht kosten könnte, das ist nur theoretisch.

In den meisten Fällen werden performancesprobleme nicht angezeigt, wo Sie sie erwarten und können nur mit Messwerkzeugen identifiziert werden, die nach dem Schreiben in Ihrem Code verwendet werden. Die häufigsten Probleme mit der performance sind I / O-bezogene oder basieren auf einem Fehler in Ihrem eigenen Code (dh das Erstellen neuer Instanzen von classn oder loops mit Millionen von Läufen, die nicht notwendig sind …) und nicht in der jdk selbst .

Ich bin ein wenig verwirrt über deine Fragen. Warum verwenden Sie kein object-relationales Mapping-Framework wie Hibernate?

Ich hatte das gleiche Problem, wenn ich viel SQL direkt lesen und schreiben musste. Irgendwann habe ich angefangen, mit Hibernate neuere Projekte zu schreiben und habe nicht zurückgeschaut. Das System kümmert sich darum, dass ich die eigentlichen Tabellen erstelle und das SQL im background laufe, und ich kann meistens mit den Java-objecten arbeiten.

Ich habe vor Jahren ein Mini-Framework erstellt, aber es war für das Prototyping und nicht für die Produktion.

Die Idee folgt und es ist sehr einfach zu tun. Der Kompromiss besteht in den Kosten für die Verwendung von Reflektion. Obwohl Hibernate und andere ORM-Tools diese Kosten ebenfalls tragen.

Die Idee ist sehr einfach.

  • Sie haben eine Dao-class, in der Sie die Abfrage ausführen.

  • Lesen Sie die ResultSet Metadata und dort können Sie den Tabellennamen, Felder, Typen usw. abfragen

  • searchn Sie im classnpfad eine class, die dem Tabellennamen entspricht und / oder die gleiche Anzahl / Typen von Feldern aufweist.

  • Legen Sie die Werte mithilfe der Reflektion fest.

  • Bringe dieses object zurück und wirf es auf die andere Seite und du bist fertig.

Es mag absurd erscheinen, die class zur Laufzeit zu finden. Und kann auch zu riskant aussehen, da sich die Abfrage möglicherweise ändert oder sich die Tabellenstruktur ändert. Aber denk darüber nach. In diesem Fall müssen Sie Ihre Mappings trotzdem aktualisieren, damit sie der neuen Struktur entsprechen. Stattdessen aktualisieren Sie einfach die passende class und leben damit zufrieden.

Mir ist nicht bekannt, wie ORM-Tools arbeiten, um die Kosten für Reflektionsaufrufe zu reduzieren (weil das Mapping das einzige, was es tut, Ihnen hilft, die passende class zu finden) In meiner Version die search unter etwa 30.000 classn (ich habe Jars aus anderen Orten hinzugefügt um es zu testing) dauerte nur .30 ms oder so ähnlich. Ich habe diese class im Cache gespeichert und beim zweiten Mal musste ich nicht nachschlagen.

Wenn Sie interessiert sind (und immer noch lesen) werde ich versuchen, die Bibliothek in meinem alten PC zu finden.

Am Ende war mein Code in etwa so:

Employee e = ( Employee ) MagicDataSource.find( "select * from employee where id = 1 "); 

oder

 Employee[] emps = ( Employee[] ) MagicDataSource.findAll("select * from employee "); 

Im Inneren war es wie:

 Object[] findAll( String query ) { ResultSet rs = getConnection().prepareStatemet( query ).executeQuery(); ResultSetMetaData md = rs.getMetadata(); String tableName = md.getTableName(); String clazz = findClass( toCamelCase( tableName ) ); // search in a list where all the class names where loaded. Class.forName( clazz ); while( rs.next() ) { for each attribute etc. etc. setter... end result.append( object ); } return result.toArray(); } 

Wenn jemand weiß, wie ORM-Tools mit Reflektionskosten umgehen, lass es mich wissen. Der Code, den ich aus Open-Source-Projekten gelesen habe, versucht nicht, etwas dagegen zu tun.

Am Ende konnte ich schnell kleine Programme für die Systemüberwachung oder solche Sachen erstellen. Ich mache diese Arbeit nicht mehr und diese Lib ist jetzt in Vergessenheit geraten.

Abgesehen von den ORMs …

Wenn Sie die Routinen rs.getString und rs.getInt verwenden, können Sie Ihren Wartungsaufwand erheblich reduzieren, wenn Sie sich auf benannte Spalten und nicht auf nummerierte Spalten verlassen.

Insbesondere rs.getInt ("id") anstelle von rs.getInt (1), zum Beispiel.

Es war selten, dass ich einen tatsächlichen datatyp für die Spaltenänderung hatte, daher ist die zukünftige SQL-Pflege etwas mehr als das Hinzufügen der neuen Spalten, die der Tabelle hinzugefügt wurden, und diese können einfach an das Ende Ihrer Monsterbindungsliste angehängt werden jeder von euch kleine DAO-objecte.

Als nächstes nehmen Sie dann dieses Idiom der Verwendung von Spaltennamen, und Sie erweitern es auf einen Plan der Verwendung von konsistenten Namen und gleichzeitig "eindeutigen" Namen. Die Absicht besteht darin, dass jeder Spalte in Ihrer database ein eindeutiger Name zugeordnet ist. Theoretisch kann es so einfach (wenn auch ausführlich) wie tabellenname_spaltenname sein. Wenn Sie also eine "member" -Tabelle haben, lautet der Spaltenname "member_id" für die ID-Spalte.

Was kauft dich das?

Sie können Ihre generischen DAOs für jedes gültige Ergebnis verwenden.

Eine "gültige" Ergebnismenge ist ein Ergebnis, das mit den Spalten festgelegt wurde, die mit Ihrer eindeutigen Benennungsspezifikation benannt wurden.

Sie erhalten also "select id member_id, name member_name von Mitglied mit id = 1".

Warum willst du das machen? Warum sollte man sich diese Mühe machen?

Denn dann werden deine Joins trivial.

 PreparedStatement = con.prepareStatement("select m.id member_id, m.name member_name, p.id post_id, p.date post_date, p.subject post_subject from member m, post p where m.id = p.member_id and m.id = 123"); ResultSet rs = ps.executeQuery(); Member m = null; Post p = null; while(rs.next()) { if (m == null) { m = MemberDAO.createFromResultSet(rs); } p = PostDAO.createFromResultSet(rs); m.addPost(p); } 

Sehen Sie, hier interessiert die Bindungslogik den Inhalt der Ergebnismenge nicht, da sie nur an Spalten interessiert ist, die sie interessieren.

In Ihren DAOs machen Sie sie etwas schlau über das ResultSet. Stellt sich heraus, wenn Sie 'rs.getInt ("member_id") und member_id nicht tatsächlich in der Ergebnismenge sein, get eine SQLException.

Aber mit ein wenig Arbeit, mit ResultSetMetaData, können Sie eine schnelle Vorabprüfung durchführen (indem Sie alle Spaltennamen im Voraus abrufen), anstatt "rs.getInt" aufzurufen, können Sie "baseDAO.getInt" aufrufen, das diese Details behandelt für Sie, um nicht die exception zu bekommen.

Das Schöne daran ist, dass Sie unvollständige DAOs einfach abrufen können, wenn Sie das einmal getan haben.

 PreparedStatement = con.prepareStatement("select m.id member_id from member m where m.id = 123"); ResultSet rs = ps.executeQuery(); Member m = null; if (rs.next()) { m = MemberDAO.createFromResultSet(rs); } 

Schließlich ist es wirklich (wirklich) ein triviales bisschen Scripting (unter Verwendung von, sagen wir, AWK), das die properties einer Bean übernehmen und sie in einen richtigen Block von Bindungscode für ein anfängliches DAO konvertieren kann. Ein ähnliches Skript kann leicht eine SQL-Tabellenanweisung übernehmen und sie in eine Java-Bean (zumindest die Basismitglieder) konvertieren, die dann von Ihrer IDE in eine Flut von Gettern / Sätzen konvertiert wird.

Durch die Zentralisierung des Bindungscodes in die DAO ist die Wartung wirklich kaum etwas, da sie an einem Ort geändert wurde. Mit partieller Bindung können Sie sie gnadenlos missbrauchen.

 PreparedStatement = con.prepareStatement("select m.name member_name, max(p.date) post_date from member m, post p where post.member_id = m.id and m.id = 123"); ResultSet rs = ps.executeQuery(); Member m = null; Post p = null; if (rs.next()) { m = MemberDAO.createFromResultSet(rs); p = MemberDAO.craateFromResultSet(rs); } System.out.println(m.getName() + " latest post was on " + p.getDate()); 

Ihre Last, die sich vorwärts bewegt, besteht hauptsächlich darin, SQL zu schreiben, aber selbst das ist nicht schrecklich. Es gibt nicht viel Unterschied zwischen dem Schreiben von SQL und EQL. Denken Sie daran, dass es eine Art Absacken ist, eine Select-statement mit einer Zillion Spalten zu schreiben, da Sie "select * from …" nicht verwenden können (und nicht verwenden sollten) (wählen Sie * immer (IMMER) führt zu) Schwierigkeiten, IME).

Aber das sind nur die Tatsachen. Ich habe jedoch festgestellt, dass dieses Problem (außer Sie berichten) einfach nicht viel passiert. Es passiert mindestens einmal für fast jeden Tisch, aber es passiert nicht immer und immer und immer wieder. Und natürlich, sobald Sie es einmal haben, können Sie entweder Ihren path zum Ruhm ausschneiden und insert oder ihn umgestalten (zB sql = "select" + MemberDAO.getAllColumns () + "," + PostDAO.getAllColumns () +) "von Mitglied m, post p").

Jetzt mag ich JPA und ORMs, ich finde sie nützlich, aber ich finde sie auch eine PITA. Es gibt eine bestimmte Liebe / Hass-Beziehung, die dort stattfindet. Und wenn alles glatt läuft, Junge, ist es glatt? Aber wenn es steinig wird – huh Junge. Dann kann es hässlich werden. Insgesamt empfehle ich sie jedoch.

Aber wenn Sie nach einem "leichten" Nicht-Framework suchen, ist diese Technik nützlich, praktisch, wenig Aufwand und gibt Ihnen viel Kontrolle über Ihre Abfragen. Es gibt einfach keine schwarze Magie oder dunkle Materie zwischen deinen Abfragen und deiner DB, und wenn die Dinge nicht funktionieren, ist es nicht irgendein geheimnisvolles Missverständnis der Framework- oder Edge-Case-Bug-Bedingung in jemandes 100K Codezeilen, sondern die Chancen sind, ein Fehler in Ihrem SQL – wo es hingehört.

Edit: Vergiss es. Während ich nach einer Lösung für mein eigenes Problem suchte, habe ich vergessen, das date auf diesem Ding zu überprüfen. Es tut uns leid. Sie können Folgendes ignorieren.

@millermj – Machst du das zum Spaß, oder weil es ein Bedürfnis gibt? Nur neugierig, denn das klingt genau wie Java IDEs wie Eclipse und NetBeans (mit der Java Persistence API) mit New-> JPA-> Entity Classes from Tables functionalität.

Ich könnte den Punkt vermissen, aber wenn jemand nur classn benötigt, die mit ihren Tabellen übereinstimmen und persistent sind, könnte die JPA plus einige IDE "Magie" gerade genug sein.