Une application centrée sur une base des données relationnelle doit implémenter les différentes requêtes de manipulation des données nécessaires à son bon fonctionnement.
En effet, la partie LMD du SQL trouve sa place au sein des applications, contrairement à la partie LDD utilisée pour créer la base des données pendant le développement et/ou le déploiement de l'application. Le langage LMD permet d'exécuter les quatre opérations de base : l'insertion, la modification, la suppression (physique, même si elle est déconseillée) et la consultation.
Garantir ces opérations nécessite la présence d'un échange dans les deux sens entre l'application et le SGBD. L'application envoie la requête (une chaîne de caractère - comme tout langage de programmation) et le SGBD répond par :
La table que vais utiliser est une table simple avec trois champs : une clé primaire (un numéro séquentiel), un titre et un contenu (tous les deux des chaînes de caractères mais la taille du contenu est très grande) :
La classe d'insertion sera ainsi :
Notez le chargement du driver avant la création de l'objet Connection :
Pur exécuter ce code (sans une interface graphique), je vais créer une petite classe :
Et je vais exécuter la ligne suivante :
Le paramètre -cp (pour CLASSPATH) indique le lieu où Java va chercher les différentes bibliothèques et fichiers class du projet. Dans cette exemple, la CLASSPATH se compose de deux parties séparées par les deux points ":" :
En vérifiant du côté MySQL, la requête "Select" permet de voir le contenu de la table :
Est ce que c'est tout ? Non. Le deuxième objectif de cet article est de mettre le point sur un problème très fréquent : les caractères spéciaux. Ces caractères peuvent poser des problèmes avec les requêtes générée se qui nous donne une requête incorrecte. A titre d'exemple, je vais changer la valeur titre de l'exemple précédent comme suit :
La même commande d'exécution me donne cette fois ci :
Alors comment faire pur régler ce problème ? Vous avez deux possibilités :
Cette amélioration ne passe pas inaperçue au niveau code : l'exécution d'une requête, qui s'effectuait en une seule étape avec Statement, devient en trois étapes avec PreparedStatement :
Et avec un changement minimal dans la classe Executer :
L'utilisation des mêmes données qui causaient le problème avec le premier exemple nous donne maintenant :
La vérification en ligne de commande par une requête "Select" en utilisant l'outil mysql nous donne :
La classe PreparedStatement est une autre classe qui permet d'exécuter des requêtes SQL. Elle ne nécessite pas des connaissances supplémentaires par rapport à la classe Statement mais elle permet de décharger le développeurs de la gestion "manuelle" des types des données et des paramètres d'une requêtes SQL.
En effet, la partie LMD du SQL trouve sa place au sein des applications, contrairement à la partie LDD utilisée pour créer la base des données pendant le développement et/ou le déploiement de l'application. Le langage LMD permet d'exécuter les quatre opérations de base : l'insertion, la modification, la suppression (physique, même si elle est déconseillée) et la consultation.
Garantir ces opérations nécessite la présence d'un échange dans les deux sens entre l'application et le SGBD. L'application envoie la requête (une chaîne de caractère - comme tout langage de programmation) et le SGBD répond par :
- Le résultat de la requête : l'ensemble des données qui répondent aux critères définis dans la requête "Select",
- Un entier : le nombre des enregistrements (lignes, occurrences, tuples) affectés par les requêtes "Insert", "Update" et "Delete".
- La classe Connection (du package java.sql) : comme son nom l'indique, il nous permet de se connecter à un SGBD et comme la logique l'impose, l'objet est créé en utilisant le pilote dédié au SGBD ainsi que les paramètres de connexion : l'adresse du serveur, le nom de l'utilisateur et son mot de passe.
- La classe Statement : c'est la classe qui nous permet d'exécuter les requêtes et de récupérer leurs résultats, pour cela, nous faisons appel aux méthodes .executeQuery() pour exécuter des requêtes de type "Select" et .executeUpdate() pour exécuter des requêtes de type "Insert into", "Update" et "Delete".
La table que vais utiliser est une table simple avec trois champs : une clé primaire (un numéro séquentiel), un titre et un contenu (tous les deux des chaînes de caractères mais la taille du contenu est très grande) :
create table Article ( id Integer primary key auto_increment, titre char(100), contenu text );
La classe d'insertion sera ainsi :
import java.io.*; import java.sql.*; public class Exemple01{ Connection con; Statement st; final String URLSGBD = "jdbc:mysql://localhost:3306/test"; final String USER = "tarek"; final String PASSWORD = "tarek"; public Exemple01(){ } public void testInserer(String titre, String contenu){ try { Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection(URLSGBD, USER, PASSWORD); st = con.createStatement(); int rs = st.executeUpdate("Insert into Article (titre, contenu) Values ('" + titre + "', '" + contenu +"')"); if(rs > 0){ System.out.println("Insertion avec succès"); } st.close(); con.close(); }catch(Exception e){ e.printStackTrace(); } } }
Notez le chargement du driver avant la création de l'objet Connection :
Class.forName("com.mysql.jdbc.Driver");
Pur exécuter ce code (sans une interface graphique), je vais créer une petite classe :
public class Executer{ public static void main(String args[]){ String titre = "Voici un premier article"; String contenu = "Et voici son contenu"; Exemple01 ex01 = new Exemple02(); ex01.testInserer(titre, contenu); } }
Et je vais exécuter la ligne suivante :
java -cp "./mysql-connector-java-5.1.38-bin.jar:." Executer
Le paramètre -cp (pour CLASSPATH) indique le lieu où Java va chercher les différentes bibliothèques et fichiers class du projet. Dans cette exemple, la CLASSPATH se compose de deux parties séparées par les deux points ":" :
- mysql-connector-java-5.1.38-bin.jar : le pilote dédié au SGBD MySQL.
- . : c'est à dire le répertoire en cours où se trouve ma classe.
En vérifiant du côté MySQL, la requête "Select" permet de voir le contenu de la table :
Est ce que c'est tout ? Non. Le deuxième objectif de cet article est de mettre le point sur un problème très fréquent : les caractères spéciaux. Ces caractères peuvent poser des problèmes avec les requêtes générée se qui nous donne une requête incorrecte. A titre d'exemple, je vais changer la valeur titre de l'exemple précédent comme suit :
String titre = "Cette apostrophe ' va causer le problème";
La même commande d'exécution me donne cette fois ci :
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'va causer le problème', 'Et voici son contenu')' at line 1 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:526) at com.mysql.jdbc.Util.handleNewInstance(Util.java:404) at com.mysql.jdbc.Util.getInstance(Util.java:387) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:939) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2547) at com.mysql.jdbc.StatementImpl.executeUpdateInternal(StatementImpl.java:1541) at com.mysql.jdbc.StatementImpl.executeLargeUpdate(StatementImpl.java:2605) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1469) at Exemple01.testInserer(Exemple01.java:24) at Executer.main(Executer.java:7)
Alors comment faire pur régler ce problème ? Vous avez deux possibilités :
- Corriger ces caractères spéciaux en ajoutant des méthodes dédiées.
- Utiliser la classe PreparedStatement.
Cette amélioration ne passe pas inaperçue au niveau code : l'exécution d'une requête, qui s'effectuait en une seule étape avec Statement, devient en trois étapes avec PreparedStatement :
- Préparation de la requête : la requête est une chaîne de caractères qui contient des paramètres. Chaque paramètre est désigné par un point d'interrogation (?).
- Passage des paramètres :cela s'effectue par les méthodes set<Type de donnée> telles que setInt, setString, etc.. Ces méthodes ressemblent aux méthodes get utilisées par la classe ResultSet.
- Exécution de la requête.
import java.io.*; import java.sql.*; public class Exemple02{ Connection con; PreparedStatement st; final String URLSGBD = "jdbc:mysql://localhost:3306/test"; final String USER = "tarek"; final String PASSWORD = "tarek"; public Exemple02(){ } public void testInserer(String titre, String contenu){ try { Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection(URLSGBD, USER, PASSWORD); String requete = "Insert into Article (titre, contenu) Values ( ?, ?)"; st = con.prepareStatement(requete); st.setString(1, titre); st.setString(2, contenu); int rs = st.executeUpdate(); if(rs > 0){ System.out.println("Insertion avec succès"); } st.close(); con.close(); }catch(Exception e){ e.printStackTrace(); } } }
Et avec un changement minimal dans la classe Executer :
public class Executer{ public static void main(String args[]){ String titre = "Cette apostrophe ' ne va pas causer des problèmes"; String contenu = "Et voici son contenu inséré grace à PreparedStatement"; Exemple02 ex02 = new Exemple02(); ex02.testInserer(titre, contenu); } }
L'utilisation des mêmes données qui causaient le problème avec le premier exemple nous donne maintenant :
Insertion avec succès
La vérification en ligne de commande par une requête "Select" en utilisant l'outil mysql nous donne :
La classe PreparedStatement est une autre classe qui permet d'exécuter des requêtes SQL. Elle ne nécessite pas des connaissances supplémentaires par rapport à la classe Statement mais elle permet de décharger le développeurs de la gestion "manuelle" des types des données et des paramètres d'une requêtes SQL.
Aucun commentaire:
La publication de nouveaux commentaires n'est pas autorisée.