Je veux construire une chaîne SQL pour manipuler la base de données (mises à jour, suppressions, insertions, sélections, ce genre de chose) - au lieu de la méthode de concaténation de chaînes horrible utilisant des millions de "+" et des guillemets illisibles au mieux - il doit être un meilleur moyen.
J'ai effectivement pensé à utiliser MessageFormat - mais il est supposé être utilisé pour les messages utilisateur, même si je pense que cela 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 le Java sql bibliothèques.
Groovy serait-il bon?
Tout d'abord, envisagez d'utiliser des 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 à faire est de conserver toutes les requêtes dans le fichier de propriétés. Par exemple, un fichier queries.properties peut placer la requête ci-dessus:
update_query=UPDATE user_table SET name=? WHERE id=?
Puis à l'aide d'une classe d'utilitaire simple:
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 pouvez utiliser vos requêtes comme suit:
PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));
C'est une solution assez simple, mais qui fonctionne bien.
Pour du SQL arbitraire, utilisez jOOQ . jOOQ prend actuellement en charge SELECT
, INSERT
, UPDATE
, DELETE
, TRUNCATE
et MERGE
. Vous pouvez créer du 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 également simplement l'exécuter à l'aide de jOOQ. Voir
(Avertissement: je travaille pour l'entreprise derrière jOOQ)
Une technologie à considérer est SQLJ - un moyen d'intégrer des instructions SQL directement en Java. Par exemple, 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 existe une étape supplémentaire de précompilation qui prend vos fichiers .sqlj et les traduit en pure Java - en bref, il recherche les blocs spéciaux délimités par
#sql
{
...
}
et les transforme en appels JDBC. L'utilisation de SQLJ présente plusieurs avantages clés:
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.
Je voudrais jeter un oeil à Spring JDBC . Je l'utilise chaque fois que j'ai besoin d'exécuter des programmes SQL par programme. Exemple:
int countOfActorsNamedJoe
= jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});
C'est vraiment génial pour tout type d'exécution SQL, en particulier les requêtes; cela vous aidera à mapper les résultats à des objets, sans ajouter la complexité d'un ORM complet.
J'ai tendance à utiliser les paramètres JDBC nommés de Spring pour pouvoir écrire une chaîne standard telle que "select * from blah where colX = ': someValue'"; Je pense que c'est assez lisible.
Une alternative serait de fournir la chaîne dans un fichier .sql séparé et de lire le contenu à l'aide d'une méthode utilitaire.
Oh, cela vaut également la peine de regarder Squill: https://squill.dev.Java.net/docs/tutorial.html
J'appuie les recommandations d'utilisation d'un ORM comme Hibernate. Cependant, il y a certainement des situations où cela ne fonctionne pas, je vais donc saisir cette occasion pour vanter certaines choses que j'ai aidé à écrire: SqlBuilder est une bibliothèque Java pour construire dynamiquement des instructions SQL en utilisant le style "constructeur". c'est assez puissant et assez flexible.
Pourquoi voulez-vous générer tout le sql à la main? Avez-vous regardé un ORM comme Hibernate? Selon votre projet, il fera probablement au moins 95% de vos besoins, utilisez-le de manière plus claire que le SQL brut, et si vous avez besoin d'obtenir les dernières performances, vous pouvez créer le Requêtes SQL devant être ajustées manuellement.
Je travaille sur une servlet Java) qui doit construire des instructions SQL très dynamiques à des fins de rapport ad hoc. La fonction de base de l'application consiste à alimenter une série de paramètres de requête HTTP nommés J'ai utilisé Spring MVC et le framework d'injection de dépendances pour stocker toutes mes requêtes SQL dans des fichiers XML et les charger dans l'application de génération de rapports, avec les informations de formatage de table. Les exigences en matière de rapport sont devenues plus compliquées que les capacités des cadres de mappage de paramètres existants et je devais écrire le mien.
Les nouveaux mappages de paramètres ressemblaient à ceci:
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
L'intérêt du framework résultant était qu'il pouvait traiter les paramètres de requête HTTP directement dans la requête avec le contrôle de type et le contrôle de limite appropriés. Aucun mappage supplémentaire requis pour la validation de l'entrée. Dans l'exemple de requête ci-dessus, le paramètre nommé serverId doit être vérifié pour s'assurer qu'il peut être converti en un entier et qu'il est compris entre 0 et 50. Le paramètre appId serait traité comme un tableau d'entiers, avec une limite de longueur de 50. Si le champ showOwner est présent et défini sur "true", les bits de SQL dans les guillemets seront ajoutés à la requête générée pour les mappages de champs facultatifs. field Plusieurs autres mappages de types de paramètres sont disponibles, y compris des segments facultatifs de SQL avec d'autres mappages de paramètres. Il permet un mappage de requête aussi complexe que le développeur peut en concevoir. Il a même des contrôles dans la configuration du rapport pour déterminer si une requête donnée aura les mappages finaux via un PreparedStatement ou s’exécutera simplement en tant que requête prédéfinie.
Pour les exemples de valeurs de demande HTTP:
showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13
Il produirait le code SQL suivant:
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
Je pense vraiment que Spring ou Hibernate ou l’un de ces frameworks devraient offrir un mécanisme de mappage plus robuste qui vérifie les types, permet des types de données complexes tels que les tableaux et autres. J'ai écrit mon moteur uniquement pour mes besoins, il n'est pas tout à fait lu pour une version générale. Cela fonctionne uniquement avec les requêtes Oracle pour le moment et tout le code appartient à une grande entreprise. Un jour, je pourrai prendre mes idées et créer un nouveau cadre open source, mais j'espère qu'un des gros joueurs existants relèvera le défi.
Vous pouvez également consulter MyBatis ( www.mybatis.org ). Il vous aide à écrire des instructions SQL en dehors de votre code Java et mappe les résultats SQL dans vos objets Java, entre autres choses].
Google fournit une bibliothèque appelée = Bibliothèque de la salle de la pièce qui fournit un moyen très propre d’écrire SQL. Ci-dessous un extrait de code du site officiel:
@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);
}
Il y a plus d'exemples et une meilleure documentation dans la documentation officielle de la bibliothèque.
Il y a aussi un appelé MentaBean qui est un Java ORM . Il a de jolies fonctionnalités et semble être un moyen assez simple d’écrire en SQL.
Vous pouvez le lire à partir d'un fichier XML. Il est facile à entretenir et à utiliser. Des analyseurs syntaxiques standard STaX, DOM et SAX sont disponibles pour en faire quelques lignes de code en Java.
Vous pouvez avoir des informations sémantiques avec des attributs sur la balise pour vous aider à utiliser davantage le code SQL. Cela peut être le nom de la méthode ou le type de requête ou tout ce qui peut vous aider à coder moins.
Vous pouvez placer le fichier XML à l'extérieur du pot et le maintenir facilement. Mêmes avantages qu'un fichier de propriétés.
XML est extensible et facilement convertible en d'autres formats.
Metamug utilise xml pour configurer REST de ressources avec SQL.
Si vous placez les chaînes SQL dans un fichier de propriétés, puis que vous les lisez, vous pouvez conserver les chaînes SQL dans un fichier texte.
Cela ne résout pas les problèmes de type SQL, mais au moins, cela facilite beaucoup le copier-coller depuis TOAD ou sqlplus.
Comment obtenir une concaténation de chaînes, outre les longues chaînes SQL de PreparedStatements (que vous pouvez facilement fournir dans un fichier texte et charger de toute façon comme ressource), que vous séparez sur plusieurs lignes?
Vous ne créez pas directement de chaînes SQL, n'est-ce pas? C'est le plus grand non-non en programmation. Veuillez utiliser PreparedStatements et fournir les données en tant que paramètres. Cela réduit considérablement le risque d'injection SQL.