118 votes

La façon la plus propre de construire une chaîne SQL en Java

Je veux construire une chaîne SQL pour faire des manipulations de base de données (mises à jour, suppressions, insertions, sélections, ce genre de choses) - au lieu de l'horrible méthode de concat de chaîne utilisant des millions de "+" et de guillemets qui est illisible au mieux - il doit y avoir un meilleur moyen.

J'ai pensé à utiliser MessageFormat - mais il est censé être utilisé pour les messages des utilisateurs, bien que je pense qu'il ferait un travail raisonnable - mais je suppose qu'il devrait y avoir quelque chose de plus aligné sur les opérations de type SQL dans les bibliothèques sql de java.

Est-ce que Groovy serait bon ?

82voto

Piotr Kochański Points 8162

Tout d'abord, pensez à utiliser les paramètres de requête dans les instructions préparées :

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

L'autre chose que l'on peut faire est de conserver toutes les requêtes dans un fichier de propriétés. Par exemple dans un fichier queries.properties on peut placer la requête ci-dessus :

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

Puis à l'aide d'une simple classe utilitaire :

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);
    }

}

vous pourriez utiliser vos requêtes comme suit :

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

Il s'agit d'une solution plutôt simple, mais qui fonctionne bien.

1 votes

Je préfère utiliser un constructeur SQL propre comme celui-ci : mentabean.soliveirajr.com

4 votes

Puis-je vous suggérer de mettre le InputStream à l'intérieur de la if (props == null) afin de ne pas l'instancier quand il n'est pas nécessaire.

0 votes

Qu'est-ce que c dans le premier et le dernier extrait de code ?

68voto

Lukas Eder Points 48046

Pour un SQL arbitraire, utilisez jOOQ . jOOQ supporte actuellement SELECT , INSERT , UPDATE , DELETE , TRUNCATE y MERGE . Vous pouvez créer le SQL comme ceci :

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();

Au lieu d'obtenir la chaîne SQL, vous pouvez aussi simplement l'exécuter, en utilisant jOOQ. Voir

http://www.jooq.org

(Clause de non-responsabilité : je travaille pour l'entreprise derrière jOOQ)

0 votes

Ne serait-ce pas, dans de nombreux cas, une mauvaise solution puisque vous ne pouvez pas laisser le dbms analyser l'instruction à l'avance avec différentes valeurs pour "5", "8", etc ? Je suppose que l'exécution avec jooq résoudrait le problème ?

0 votes

@Vegard : Vous avez un contrôle total sur la façon dont jOOQ doit rendre les valeurs de liaison dans sa sortie SQL : jooq.org/doc/3.1/manuel/sql-building/bind-values . En d'autres termes, vous pouvez choisir de rendre ou non "?" ou s'il faut mettre en ligne les valeurs de liaison.

0 votes

Oui, mais en ce qui concerne les façons propres de construire le sql, ce serait un code un peu désordonné à mes yeux si vous n'utilisez pas JOOQ pour exécuter. dans cet exemple vous mettez A à 1, B à 2 etc, mais vous devez le faire une fois de plus lorsque vous exécutez si vous n'exécutez pas avec JOOQ.

15voto

Ashley Mercer Points 1033

Une technologie que vous devriez envisager est SQLJ - un moyen d'intégrer des instructions SQL directement dans Java. À titre d'exemple simple, vous pourriez avoir les éléments suivants dans un fichier appelé TestQueries.sqlj :

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

Il y a une étape supplémentaire de précompilation qui prend vos fichiers .sqlj et les traduit en Java pur - en bref, il recherche les blocs spéciaux délimités avec

#sql
{
    ...
}

et les transforme en appels JDBC. L'utilisation de SQLJ présente plusieurs avantages majeurs :

  • fait totalement abstraction de la couche JDBC : les programmeurs ne doivent penser qu'à Java et à SQL.
  • le traducteur peut vérifier la syntaxe de vos requêtes par rapport à la base de données au moment de la compilation.
  • la possibilité de lier directement les variables Java dans les requêtes en utilisant le préfixe " :".

Il existe des implémentations du traducteur pour la plupart des principaux fournisseurs de bases de données, vous devriez donc pouvoir trouver facilement tout ce dont vous avez besoin.

1 votes

Celle-ci est maintenant dépassée, selon wikipedia.

2 votes

Au moment de la rédaction de ce document (janvier 2016), SQLJ est désigné par les termes suivants sur Wikipédia comme "périmée" sans aucune référence. A-t-il été officiellement abandonné ? Si oui, je collerai un avertissement en haut de cette réponse.

0 votes

NB : La technologie est toujours supportée, par exemple dans la la dernière version d'Oracle, 12c . J'admets qu'il ne s'agit pas de la norme la plus moderne, mais elle fonctionne toujours et présente certains avantages (comme la vérification au moment de la compilation des requêtes contre la base de données) qui ne sont pas disponibles dans d'autres systèmes.

13voto

tcurdt Points 4916

Je me demande si vous cherchez quelque chose comme Squiggle ( GitHub ). Un autre élément très utile est jDBI . Mais cela ne vous aidera pas à répondre aux questions.

9voto

Je jetterais un coup d'œil à Spring JDBC . Je l'utilise chaque fois que j'ai besoin d'exécuter des SQLs de manière programmatique. Exemple :

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

Il est vraiment idéal pour tout type d'exécution SQL, en particulier pour les requêtes ; il vous aidera à faire correspondre des ensembles de résultats à des objets, sans ajouter la complexité d'un ORM complet.

0 votes

Comment puis-je obtenir une requête sql réellement exécutée ? Je veux l'enregistrer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X