it-swarm.com.de

Der sauberste Weg, um eine SQL-Zeichenfolge in Java

Ich möchte eine SQL-Zeichenfolge erstellen, um die Datenbank zu manipulieren (Aktualisieren, Löschen, Einfügen, Auswählen usw.) - anstelle der schrecklichen String-Concat-Methode, bei der Millionen von "+" und Anführungszeichen verwendet werden, die bestenfalls unlesbar sind muss ein besserer Weg sein.

Ich habe überlegt, MessageFormat zu verwenden - aber es sollte für Benutzer-Nachrichten verwendet werden, obwohl ich denke, dass es einen vernünftigen Job machen würde -, aber ich denke, es sollte etwas mehr für SQL-Typ-Operationen in der SQL-Datei Java geben Bibliotheken.

Wäre Groovy gut?

95
Vidar

Erwägen Sie zunächst die Verwendung von Abfrageparametern in vorbereiteten Anweisungen:

PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?");
stm.setString(1, "the name");
stm.setInt(2, 345);
stm.executeUpdate();

Die andere Möglichkeit besteht darin, alle Abfragen in der Eigenschaftendatei zu speichern. Beispielsweise kann in einer queries.properties-Datei die obige Abfrage platziert werden:

update_query=UPDATE user_table SET name=? WHERE id=?

Dann mit Hilfe einer einfachen Utility-Klasse:

public class Queries {

    private static final String propFileName = "queries.properties";
    private static Properties props;

    public static Properties getQueries() throws SQLException {
        InputStream is = 
            Queries.class.getResourceAsStream("/" + propFileName);
        if (is == null){
            throw new SQLException("Unable to load property file: " + propFileName);
        }
        //singleton
        if(props == null){
            props = new Properties();
            try {
                props.load(is);
            } catch (IOException e) {
                throw new SQLException("Unable to load property file: " + propFileName + "\n" + e.getMessage());
            }           
        }
        return props;
    }

    public static String getQuery(String query) throws SQLException{
        return getQueries().getProperty(query);
    }

}

sie könnten Ihre Abfragen wie folgt verwenden:

PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));

Dies ist eine ziemlich einfache Lösung, funktioniert aber gut.

67

Verwenden Sie für beliebiges SQL jOOQ . jOOQ unterstützt derzeit SELECT, INSERT, UPDATE, DELETE, TRUNCATE und MERGE. Sie können SQL wie folgt erstellen:

String sql1 = DSL.using(SQLDialect.MYSQL)  
                 .select(A, B, C)
                 .from(MY_TABLE)
                 .where(A.equal(5))
                 .and(B.greaterThan(8))
                 .getSQL();

String sql2 = DSL.using(SQLDialect.MYSQL)  
                 .insertInto(MY_TABLE)
                 .values(A, 1)
                 .values(B, 2)
                 .getSQL();

String sql3 = DSL.using(SQLDialect.MYSQL)  
                 .update(MY_TABLE)
                 .set(A, 1)
                 .set(B, 2)
                 .where(C.greaterThan(5))
                 .getSQL();

Anstatt den SQL-String abzurufen, können Sie ihn auch einfach mit jOOQ ausführen. Sehen

http://www.jooq.org

(Haftungsausschluss: Ich arbeite für die Firma hinter jOOQ)

59
Lukas Eder

Eine Technologie, die Sie in Betracht ziehen sollten, ist SQLJ - eine Möglichkeit, SQL-Anweisungen direkt in Java einzubetten. Als einfaches Beispiel könnte in einer Datei mit dem Namen TestQueries.sqlj Folgendes enthalten sein:

public class TestQueries
{
    public String getUsername(int id)
    {
        String username;
        #sql
        {
            select username into :username
            from users
            where pkey = :id
        };
        return username;
    }
}

Es gibt einen zusätzlichen Vorkompilierungsschritt, bei dem Ihre .sqlj-Dateien in reine Java) übersetzt werden - kurz gesagt, es wird nach den speziellen Blöcken gesucht, die durch begrenzt sind

#sql
{
    ...
}

und verwandelt sie in JDBC-Aufrufe. Die Verwendung von SQLJ bietet mehrere wichtige Vorteile:

  • entfernt die JDBC - Ebene vollständig - Programmierer müssen nur über Java und SQL nachdenken
  • der Übersetzer kann veranlassen, dass Ihre Abfragen beim Kompilieren auf Syntax usw. gegen die Datenbank abgeglichen werden
  • möglichkeit, Java Variablen in Abfragen mit dem Präfix ":" direkt zu binden

Es gibt Implementierungen des Übersetzers für die meisten großen Datenbankanbieter, daher sollten Sie in der Lage sein, alles zu finden, was Sie brauchen.

14
Ashley Mercer

Ich frage mich, ob Sie nach etwas wie Squiggle sind. Sehr nützlich ist auch jDBI . Es wird Ihnen jedoch bei den Abfragen nicht helfen.

12
tcurdt

Ich würde mir Spring JDBC ansehen. Ich benutze es, wenn ich SQLs programmgesteuert ausführen muss. Beispiel:

int countOfActorsNamedJoe
    = jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});

Es ist wirklich großartig für jede Art von SQL-Ausführung, insbesondere für Abfragen. Es hilft Ihnen, Ergebnismengen Objekten zuzuordnen, ohne die Komplexität eines vollständigen ORM zu erhöhen.

9

Ich neige dazu, Spring's Named JDBC-Parameter zu verwenden, damit ich einen Standard-String wie "select * from blah where colX = ': someValue'" schreiben kann. Ich denke das ist ziemlich lesbar.

Eine Alternative wäre, die Zeichenfolge in einer separaten .sql-Datei bereitzustellen und den Inhalt mit einer Dienstprogrammmethode einzulesen.

Oh, auch ein Blick auf Squill lohnt sich: https://squill.dev.Java.net/docs/tutorial.html

5
GaryF

Ich stimme den Empfehlungen für die Verwendung eines ORM wie Hibernate zu. Es gibt jedoch sicherlich Situationen, in denen dies nicht funktioniert. Daher werde ich diese Gelegenheit nutzen, um einige Dinge anzukündigen, bei deren Schreiben ich geholfen habe: SqlBuilder ist eine Java Bibliothek zum dynamischen Erstellen von SQL-Anweisungen im "Builder" -Stil. es ist ziemlich mächtig und ziemlich flexibel.

4
james

Warum möchten Sie den gesamten SQL-Code von Hand generieren? Haben Sie sich ein ORM wie Hibernate angesehen? Abhängig von Ihrem Projekt wird es wahrscheinlich mindestens 95% von dem tun, was Sie benötigen. Tun Sie es auf eine sauberere Art und Weise als Raw SQL SQL-Abfragen, die manuell optimiert werden müssen.

4
Jared

Ich habe an einer Java Servlet-Anwendung gearbeitet, die sehr dynamische SQL-Anweisungen für Ad-hoc-Berichtszwecke erstellen muss. Die Grundfunktion der App besteht darin, eine Reihe von benannten HTTP-Anforderungsparametern in eine Pre-Datei einzugeben Ich habe mit Spring MVC und dem Abhängigkeitsinjektionsframework alle meine SQL-Abfragen in XML-Dateien gespeichert und sie zusammen mit den Tabellenformatierungsinformationen in die Berichtsanwendung geladen Die Berichtsanforderungen wurden komplizierter als die Funktionen der vorhandenen Parameterzuordnungs-Frameworks, und ich musste meine eigenen schreiben. Es war eine interessante Übung in der Entwicklung und erstellte ein Framework für die Parameterzuordnung, das viel robuster war als alles andere, was ich finden konnte.

Die neuen Parameterzuordnungen sahen folgendermaßen aus:

select app.name as "App", 
       ${optional(" app.owner as "Owner", "):showOwner}
       sv.name as "Server", sum(act.trans_ct) as "Trans"
  from activity_records act, servers sv, applications app
 where act.server_id = sv.id
   and act.app_id = app.id
   and sv.id = ${integer(0,50):serverId}
   and app.id in ${integerList(50):appId}
 group by app.name, ${optional(" app.owner, "):showOwner} sv.name
 order by app.name, sv.name

Das Schöne an dem resultierenden Framework war, dass es HTTP-Anforderungsparameter direkt in der Abfrage mit der richtigen Typprüfung und Limitprüfung verarbeiten konnte. Für die Eingabevalidierung sind keine zusätzlichen Zuordnungen erforderlich. In der obigen Beispielabfrage würde der Parameter serverId überprüft, um sicherzustellen, dass er in eine Ganzzahl umgewandelt werden kann und im Bereich von 0 bis 50 liegt. Der Parameter appId würde als Array von Ganzzahlen mit einer Längenbeschränkung von 50 verarbeitet. Wenn das Feld showOwner vorhanden und auf "true" gesetzt ist, werden die SQL-Bits in den Anführungszeichen wird der generierten Abfrage für die optionalen Feldzuordnungen hinzugefügt. field Es stehen mehrere weitere Parametertypzuordnungen zur Verfügung, einschließlich optionaler SQL-Segmente mit weiteren Parameterzuordnungen. Dies ermöglicht eine so komplexe Abfragezuordnung, wie es der Entwickler sich vorstellen kann. In der Berichtskonfiguration können Sie sogar steuern, ob eine bestimmte Abfrage die endgültigen Zuordnungen über ein PreparedStatement enthält oder einfach als vorgefertigte Abfrage ausgeführt wird.

Für die Beispiel-HTTP-Anforderungswerte:

showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13

Es würde das folgende SQL erzeugen:

select app.name as "App", 
       app.owner as "Owner", 
       sv.name as "Server", sum(act.trans_ct) as "Trans"
  from activity_records act, servers sv, applications app
 where act.server_id = sv.id
   and act.app_id = app.id
   and sv.id = 20
   and app.id in (1,2,3,5,7,11,13)
 group by app.name,  app.owner,  sv.name
 order by app.name, sv.name

Ich denke wirklich, dass Spring oder Hibernate oder eines dieser Frameworks einen robusteren Zuordnungsmechanismus bieten sollte, der Typen überprüft, komplexe Datentypen wie Arrays und andere solche Features zulässt. Ich habe meine Engine nur für meine Zwecke geschrieben, sie ist für die allgemeine Veröffentlichung nicht ganz gelesen. Derzeit funktioniert es nur mit Oracle-Abfragen, und der gesamte Code gehört einem großen Unternehmen. Irgendwann nehme ich vielleicht meine Ideen auf und baue ein neues Open-Source-Framework auf, aber ich hoffe, dass einer der bestehenden Big Player die Herausforderung annimmt.

3
Natalia

Sie können sich auch MyBatis ( www.mybatis.org ) ansehen. Es hilft Ihnen, SQL-Anweisungen außerhalb Ihres Java - Codes zu schreiben und die SQL-Ergebnisse unter anderem Ihren Java - Objekten zuzuordnen.

3
joshua

Google stellt eine Bibliothek mit dem Namen Room Persitence Library zur Verfügung, die eine sehr saubere Art des Schreibens von SQL bietet. Bellow ist ein kurzer Codeausschnitt von der offiziellen Website:

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND "
           + "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

Weitere Beispiele und eine bessere Dokumentation finden Sie in den offiziellen Dokumenten der Bibliothek.

Es gibt auch eine MentaBean mit dem Namen Java ORM . Es hat nette Funktionen und scheint eine ziemlich einfache Art zu sein, SQL zu schreiben.

3
CasualCoder3

Lesen Sie eine XML-Datei.

Sie können es aus einer XML-Datei lesen. Es ist einfach zu warten und zu bearbeiten. Es gibt Standard-STaX-, DOM- und SAX-Parser, die dafür sorgen, dass Java nur wenige Codezeilen enthält.

Machen Sie mehr aus Attributen

Sie können einige semantische Informationen mit Attributen auf dem Tag haben, um mehr mit dem SQL zu tun. Dies kann der Methodenname oder der Abfragetyp sein oder alles, was Ihnen hilft, weniger zu codieren.

Wartung

Sie können die XML-Datei außerhalb des Glases platzieren und problemlos warten. Gleiche Vorteile wie bei einer Eigenschaftendatei.

Umwandlung

XML ist erweiterbar und kann problemlos in andere Formate konvertiert werden.

Anwendungsfall

Metamug verwendet XML, um REST Ressourcendateien mit SQL. zu konfigurieren

2
Sorter

Wenn Sie die SQL-Zeichenfolgen in eine Eigenschaftendatei einfügen und diese dann lesen, können Sie die SQL-Zeichenfolgen in einer Nur-Text-Datei speichern.

Damit sind die Probleme mit dem SQL-Typ nicht gelöst, aber zumindest wird das Kopieren und Einfügen von TOAD oder sqlplus viel einfacher.

1
Rowan

Wie erhalten Sie die Verkettung von Zeichenfolgen, abgesehen von langen SQL-Zeichenfolgen in PreparedStatements (die Sie problemlos in einer Textdatei bereitstellen und trotzdem als Ressource laden können), die Sie über mehrere Zeilen aufteilen?

Sie erstellen nicht direkt SQL-Zeichenfolgen, oder? Das ist das größte Nein-Nein in der Programmierung. Bitte verwenden Sie PreparedStatements und geben Sie die Daten als Parameter an. Dies verringert die Wahrscheinlichkeit von SQL Injection erheblich.

0
JeeBee