JAVA ET SQL JDBC Java - JDBC SOMMAIRE Chapitre 1 1.1 1.2 - JDBC ............................................................................ 4 Présentation ............................................................................................. 5 Se Connecter à la Base et Parcourir un curseur ........................................... 6 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 Objectif..................................................................................................................... 6 Ecran ........................................................................................................................ 6 Principes et démarche ............................................................................................... 6 Principales méthodes utilisées .................................................................................... 7 Script ........................................................................................................................ 8 Commentaires ........................................................................................................... 9 Gestion avancée des curseurs ...................................................................................11 Schéma résumé .......................................................................................................12 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 Objectif....................................................................................................................13 Principes et démarche ..............................................................................................13 Principales méthodes utilisées ...................................................................................13 Insertion d'un enregistrement ...................................................................................13 Commentaires ..........................................................................................................14 Suppression d'un enregistrement...............................................................................14 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 Objectif....................................................................................................................15 Principes et démarche ..............................................................................................15 Méthodes utilisées ....................................................................................................15 Script .......................................................................................................................15 Commentaires ..........................................................................................................17 Alternative pour la récupération des valeurs ...............................................................18 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 Objectif....................................................................................................................19 Principes et démarche ..............................................................................................19 Méthodes utilisées ....................................................................................................19 Script .......................................................................................................................19 Commentaires ..........................................................................................................20 1.6.1 1.6.2 Principe et démarche ................................................................................................21 Exemples .................................................................................................................21 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 Objectif....................................................................................................................22 Principes et démarche ..............................................................................................22 Méthodes utilisées ....................................................................................................22 La procédure stockée Oracle .....................................................................................23 La procédure stockée MySQL ....................................................................................23 Script pour MySQL ....................................................................................................24 Script pour Oracle ....................................................................................................24 Commentaires ..........................................................................................................25 1.9.1 1.9.2 Objectif....................................................................................................................28 Principes et démarche ..............................................................................................28 1.3 1.4 1.5 1.6 1.7 1.8 1.9 Mises à jour dans la BD ........................................................................... 13 Récupération dynamique du résultat d'un Select ....................................... 15 La méthode Execute() ............................................................................. 19 SQL dynamique (Préparé) ........................................................................ 21 Exécuter une procédure stockée avec des paramètres IN .......................... 22 Exécuter une procédure stockée qui renvoie un SELECT ............................ 26 Exécuter une procédure stockée avec des paramètres OUT ....................... 28 16 avril 2017 - Page 2 Java - JDBC 1.9.3 1.9.4 1.9.5 1.9.6 1.10 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.10.6 1.10.7 1.11 1.11.1 1.11.2 1.11.3 1.12 1.13 Méthodes utilisées ....................................................................................................28 La procédure stockée Oracle .....................................................................................29 Script .......................................................................................................................30 Commentaires ..........................................................................................................31 Exécuter une fonction stockée ............................................................... 32 Objectif....................................................................................................................32 Principes et démarche ..............................................................................................32 Méthodes utilisées ....................................................................................................32 La fonction stockée Oracle ........................................................................................33 La fonction stockée MySQL .......................................................................................33 Script .......................................................................................................................34 Commentaires ..........................................................................................................35 Accès à la MetaBase ............................................................................. 36 Objectif et démarche ................................................................................................36 Quelques méthodes ..................................................................................................36 Script .......................................................................................................................37 Un curseur "scrollable".......................................................................... 38 Un curseur "updatable" ......................................................................... 39 Chapitre 2 2.1 - ANNEXES .................................................................... 40 Une seule classe pour la gestion BD ......................................................... 41 2.1.1 2.1.2 2.1.3 Objectif....................................................................................................................41 Exemple ..................................................................................................................42 Code de la classe .....................................................................................................42 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 Class.forName ..........................................................................................................43 DriverManager.getConnection ...................................................................................43 Connection.close ......................................................................................................44 createStatement .......................................................................................................44 executeQuery ...........................................................................................................45 Tableaux des Classes et Interfaces ............................................................................46 2.3.1 2.3.2 Bd2Fichier ................................................................................................................49 Fichier2Bd ................................................................................................................51 2.4.1 2.4.2 2.4.3 ODBC (Open DataBase Connectivity) .........................................................................52 JDBC-MySQL ............................................................................................................54 JDBC-Oracle (Java DataBase Connectivity) .................................................................55 2.5.1 2.5.2 2.5.3 Le modèle ................................................................................................................56 Le JavaBean.............................................................................................................57 Le DAO ....................................................................................................................59 2.2 2.3 2.4 2.5 2.6 Quelques méthodes pour la manipulation des BD ...................................... 43 Transferts BD-Fichier ............................................................................... 49 Les pilotes .............................................................................................. 52 Le pattern DAO et les Beans .................................................................... 56 Introspection et SQL ............................................................................... 64 16 avril 2017 - Page 3 Java - JDBC CHAPITRE 1 - JDBC 16 avril 2017 - Page 4 Java - JDBC 1.1 PRESENTATION Ce chapitre a pour objectif de vous introduire à la technologie JAVA-BD de type C/S (Client/Serveur) de première et deuxième génération. Cela comprend : L'accès à une BD (Base de Données) La manipulation des données avec les ordres SQL de base. pour la première génération et la manipulation des données avec : des procédures stockées des fonctions stockées pour la deuxième génération. Nous retrouverons la gestion de données relationnelles dans d'autres chapitres : SQL et AWT SQL et SWING JAVA et la technologie n-tiers avec les Applets, les Servlets, les JSP, … Les exemples et exercices sont principalement basés sur une BD MySQL. Quelques-uns avec Oracle. De toutes façons ils sont facilement adaptables à toutes BD (Oracle, SQL Server, MsAccess, ODBC, …). 16 avril 2017 - Page 5 Java - JDBC 1.2 1.2.1 SE CONNECTER A LA BASE ET PARCOURIR UN CURSEUR Objectif Se connecter à une BD et afficher les enregistrements d'une table. 1.2.2 Ecran 1.2.3 Principes et démarche Se connecter à la base de données, Créer un objet de type Statement (Nécessaire pour exécuter un ordre SQL statique), Ouvrir un curseur, Afficher les enregistrements, Fermer le curseur, Se déconnecter. Créez un nouveau projet nommé projetSQL. Dans ce projet créez un nouveau package nommé packageSQL. Ajoutez le fichier .jar du pilote. Note : pour les différents types de connexions (Oracle, MySQL, ODBC, …) cf dans les annexes du support le paragraphe Les pilotes. Ensuite créez une première classe nommée VillesSelect. 16 avril 2017 - Page 6 Java - JDBC 1.2.4 Principales méthodes utilisées Méthodes Class.forName("pilote") Cn = DriverManager.getConnection("url", "user","pwd") Cmd = Connection.createStatement() Rs = Statement.executeQuery("SELECT") ResultSet.next() ResultSet.getString(indexColonne) close() Fonctionnalités Monter le pilote d'accès à la BD Permet de se connecter et renvoie une connexion Crée un objet de type Statement (instruction) Exécute une requête et renvoie un curseur Avance dans le curseur; renvoie False à la fin du curseur et True autrement. Récupère une valeur string dans une colonne de curseur. Les méthodes getXXX() permettent la récupération de tous les types. Ferme un curseur, un statement, une connexion. Si le pilote le permet ainsi que le gestionnaire de curseur vous pouvez scroller un curseur et faire des MAJ à partir de celui-ci. Ceci via le paramétrage du createStatement(). Connection.createStatement(ResultSet.TYPE_SCROLL , ResultSet.CONCURRENCY); cf en annexe les valeurs possibles et les supports AWT et SWING pour la mise en place. Note sur la méthode next() du ResultSet : La méthode next() avance dans le curseur et renvoie un booléen. Voici un exemple de recherche d'un enregistrement. Le test évite ainsi une levée d'exception. ResultSet lrs = lstSql.executeQuery(lsSelect); if(lrs.next()) lsResultat = lrs.getString(1); else lsResultat = "Introuvable"; 16 avril 2017 - Page 7 Java - JDBC 1.2.5 Script package packageSQL; import java.sql.*; public class VillesSelect { public static void main(String[] args) { // --- Déclarations Connection lcConnexion = null; Statement lstSql = null; ResultSet lrs = null; // --- Pour une connexion ORACLE avec un pilote natif oracle //String lsPilote = "oracle.jdbc.driver.OracleDriver"; //String lsConnexion = "jdbc:oracle:thin:@localhost:1521:xe"; // --- Pour une connexion ORACLE via OBDC //String lsPilote = "sun.jdbc.odbc.JdbcOdbcDriver"; //String lsConnexion = "jdbc:odbc:dsn_bd_oracle"; // --- Pour une connexion MySQL native String lsPilote = "org.gjt.mm.mysql.Driver"; String lsConnexion = "jdbc:mysql://localhost/cours"; String lsUt = "root"; String lsMdp = ""; String lsSelect = "SELECT * FROM villes"; try { Class.forName(lsPilote); lcConnexion = DriverManager.getConnection(lsConnexion,lsUt,lsMdp); lstSql = lcConnexion.createStatement(); lrs = lstSql.executeQuery(lsSelect); while(lrs.next()) { System.out.println(lrs.getString(1) + "-" + lrs.getString(2)); } lrs.close(); lstSql.close(); lcConnexion.close(); lrs = null; lstSql = null; lcConnexion = null; } catch(ClassNotFoundException err) { System.err.println(err.getMessage()); } catch(SQLException err) { System.err.println(err.getMessage()); } } } 16 avril 2017 - Page 8 Java - JDBC 1.2.6 Commentaires 1.2.6.1 Les interfaces utilisées Interfaces Connection Statement RecordSet Fonctions Interface permettant de se connecter à la base Interface permettant de "créer" des commandes Interface curseur 1.2.6.2 La connexion Les classes et les interfaces utilisées sont dans le package java.sql import java.sql.*; La connexion se fait en deux temps : On définit d'abord la classe de pilotes que l'on utilise avec la méthode forName de la classe Class (package java.lang) à laquelle on passe comme paramètre le nom complet du package et de la classe. Class.forName("oracle.jdbc.driver.OracleDriver"); // Pour Oracle Natif Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Pour Oracle via ODBC Ensuite on tente une connexion en utilisant la méthode getConnection de la classe DriverManager (du package java.sql). // --- Pour Oracle natif lcConnexion = DriverManager.getConnection("jdbc:oracle:thin:@140.0.0.68:1521:orcl" , lsUt, lsMdp); // --- Pour Oracle Via ODBC lcConnexion = DriverManager.getConnection("jdbc:odbc:dsn_bd_nt_orac",lsUt,lsMdp); L'adresse de la base est formée comme une URL avec le format suivant : protocole:sous_protocole:nom_de_la_base. 1.2.6.3 L'ouverture du curseur Avant d'ouvrir un curseur il faut créer un objet Statement – qui peut être traduit par instruction ou commande - avec la méthode createStatement d'un objet de type Connection. lstSql = lcConnexion.createStatement(); Ensuite la méthode executeQuery de l'objet Statement est exécutée. lrs = lstSql.executeQuery(lsSelect); 16 avril 2017 - Page 9 Java - JDBC 1.2.6.4 Le parcours du curseur On utilise la méthode next() - qui renvoie un booléen – de la classe RecordSet. On utilise la méthode getString(nom_de_colonne | numéro_de_colonne) de l'objet RecordSet pour récupérer les valeurs de type String; l'indice commence à 1. while(lrs.next()) { lsCp = lrs.getString(1); } 1.2.6.5 La fermeture du curseur On utilise la méthode Close() de la classe RecordSet. lrs.close(); // Fermeture du curseur lstSql.close(); // Fermeture du Statement 1.2.6.6 La déconnexion On utilise la méthode close() de la classe Connection. lcConnexion.close(); // Fermeture de la connexion 1.2.6.7 Les exceptions Les instructions du script peuvent générer deux types d'erreur : Classe introuvable : ceci concerne le pilote Erreur SQL Ces erreurs sont gérées par les exceptions suivantes : catch(ClassNotFoundException err) { System.err.println("\nPilote BD non trouvé"); } catch(SQLException err) { System.err.println(err.getMessage()); } 16 avril 2017 - Page 10 Java - JDBC 1.2.7 Gestion avancée des curseurs Présentation Le curseur utilisé précédemment est un curseur en lecture seule et en avant seulement. Il est possible de l'ouvrir en d'autres modes. Read Only Read Write En avant Par défault Impossible Dans tous les sens Scroll + Lecture Scroll + écriture Syntaxe Cn.createStatement(sens, lecture) Valeurs des paramètres : Constante ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE Description En avant Tous les sens Tous les sens ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE Lecture seule Lecture/Ecriture 16 avril 2017 - Page 11 Java - JDBC 1.2.8 Schéma résumé C Exercice Créez un nouveau projet nommé projetBD. Dans ce projet créez un nouveau package nommé packageBD. Créez une classe BD avec les méthodes seConnecter("bd","ut","mdp"), seDeconnecter() et getCurseurCSV("select"). La connexion est un attribut de la classe. La méthode seConnecter() renvoie une StringBuilder qui contiendra soit OK soit une message d'erreur. La méthode seDeconnecter() renvoie un booléen. La méthode getCurseurCSV("select") renvoie une StringBuilder. Lorsque nous voudrons réutiliser cette classe dans le projet projetSQL, il faudra au préalable ajouter le fichier projetBD.jar au projet projetSQL. Dans NetBeans : Soit Projet/Clic droit/Propriétés/Bibliothèque/Ajouter un fichier jar/ … Soit Bibliothèques/ Ajouter un fichier jar/ … 16 avril 2017 - Page 12 Java - JDBC 1.3 MISES A JOUR DANS LA BD 1.3.1 Objectif Réaliser des mises à jour (Insertion, Suppression, Modification) dans une BD. 1.3.2 Principes et démarche Se connecter à la base de données, Créer un objet de type Statement, Exécuter une instruction de mise à jour, Valider, Se déconnecter. 1.3.3 Principales méthodes utilisées Méthodes Fonctionnalités Connection.setAutoCommit(boolean) Permet de basculer le mode automatique de commitment. Statement.executeUpdate(sql) Connection.rollback() Connection.commit() Exécute une instruction SQL de mise à jour. Cette méthode renvoie un int qui correspond au nombre de lignes mises à jour. Invalide la transaction. Valide la transaction. 1.3.4 Insertion d'un enregistrement package packageSQL; import java.sql.*; public class VillesInsert { public static void main(String[] args) { // --- Déclarations Connection lcConnexion = null; Statement lstSql; String lsInsert; int liNum; // --- Instructions de connexion try { Class.forName("org.gjt.mm.mysql.Driver"); lcConnexion = DriverManager.getConnection("jdbc:mysql://localhost/cours","root",""); lcConnexion.setAutoCommit(false); lstSql = lcConnexion.createStatement(); lsInsert = "INSERT INTO villes(cp, nom_ville, id_pays) VALUES('14000','Caen','033')"; liNum = lstSql.executeUpdate(lsInsert); 16 avril 2017 - Page 13 Java - JDBC System.out.println("Nombre d'insert : " + liNum); lcConnexion.commit(); lstSql.close(); lcConnexion.close(); } catch(ClassNotFoundException err) { System.err.println("\nPilote BD non trouvé"); } catch(SQLException err) { System.err.println(err); } } } 1.3.5 Commentaires 1.3.5.1 Insertion On utilise la méthode executeUpdate() de l'interface Statement pour exécuter une mise à jour dans la BD. liNum = lstSql.executeUpdate(lsInsert); 1.3.5.2 Validation Vous validez avec la méthode commit() appliquée à l'interface de type Connection. lcConnexion.commit(); 1.3.6 Suppression d'un enregistrement Script lsDelete = "DELETE FROM villes WHERE cp = '14000'"; liNum = lstSql.executeUpdate(lsDelete); System.out.println("Nombre de suppression : " + liNum); lcConnexion.commit(); Commentaires La méthode utilisée est la même; la différence est que vous envoyez un ordre SQL DELETE à la place d'un ordre INSERT. Il en serait de même pour une mise à jour au sens strict avec l'instruction SQL UPDATE. Exercice Ajoutez les méthodes supprimer() et inserer() à la classe BD. 16 avril 2017 - Page 14 Java - JDBC 1.4 RECUPERATION DYNAMIQUE DU RESULTAT D'UN SELECT 1.4.1 Objectif Pouvoir récupérer les valeurs extraites à partir d'un SELECT quel que soit le nombre de colonnes et le type des colonnes. 1.4.2 Principes et démarche Connexion à la base et ouverture d'un curseur en exécutant un ordre SQL Select, Récupération de la structure du curseur dans un objet ResultSetMetaData, Récupération du nombre de colonnes, Pour chaque colonne récupération du nom de la colonne, Pour chaque colonne (pour chaque ligne) récupération de la valeur de la colonne. 1.4.3 Méthodes utilisées Méthodes Rs.getMetaData() Rsmd.getColumnCount() Rsmd.getColumnName(index) Rsmd.getColumnType(index) Rs.getObject(rang) Rs.getString(rang) Renvoie Renvoie Renvoie Renvoie Renvoie Renvoie Fonctionnalités la structure du SELECT le nombre de colonnes de la structure le nom de la colonne le type de la colonne un objet d'une structure une string 1.4.4 Script package packageSQL; import java.sql.*; public class RsDynamique { public static void main(String[] args) { // --- Déclarations Connection lcConnexion = null; Statement lstSql = null; ResultSet lrs = null; ResultSetMetaData lrsmd = null; String lsSelect = ""; String lsLigne = ""; int liCols, i; Object loValeur; try { Class.forName("org.gjt.mm.mysql.Driver"); lcConnexion = DriverManager.getConnection("jdbc:mysql://localhost/cours","root",""); lstSql = lcConnexion.createStatement(); 16 avril 2017 - Page 15 Java - JDBC //lsSelect lsSelect lrs lrsmd liCols = = = = = "SELECT * FROM villes"; "SELECT * FROM clients"; lstSql.executeQuery(lsSelect); lrs.getMetaData(); lrsmd.getColumnCount(); // --- Affichage des en-têtes des colonnes for(i=1; i<=liCols; ++i) { lsLigne += lrsmd.getColumnName(i) + "-"; } System.out.println(lsLigne); // --- Affichage du contenu des colonnes while(lrs.next()) { lsLigne = ""; for(i=1; i<=liCols; i++) { loValeur = lrs.getObject(i); if(loValeur == null) lsLigne += "NUL -"; else lsLigne += loValeur.toString() + "-"; } System.out.println(lsLigne); } lrs.close(); lstSql.close(); lcConnexion.close(); lrs = null; lstSql = null; lcConnexion = null; } catch(ClassNotFoundException err) { System.err.println("Pilote non monté : " + err); } catch(SQLException err) { System.err.println("Erreur SQL : " + err); } } } 16 avril 2017 - Page 16 Java - JDBC 1.4.5 Commentaires 1.4.5.1 Ouverture du curseur Le curseur est créé et ouvert avec la méthode executeQuery() de l'objet Statement. La chaîne passée en argument est l'ordre Select. lrs = lstSql.executeQuery(lsSelect); 1.4.5.2 Récupération de la structure La structure du curseur est récupérée avec la méthode getMetaData() de l'objet RecordSet. Cette méthode renvoie la structure dans un objet de type ResultSetMetaData. lrsmd = lrs.getMetaData(); 1.4.5.3 Récupération des éléments de la structure On récupère le nombre de colonnes avec la méthode getColumnCount() de l'objet ResultSetMetaData. liCols = lrsmd.getColumnCount(); On récupère le nom de chaque colonne avec la méthode getColumnName(position) de l'objet ResultSetMetaData. lsNomCol = lrsmd.getColumnName(i); 1.4.5.4 Récupération des valeurs On récupère la valeur en transformant en String l'extraction de l'objet correspondant pour la ligne en cours à la colonne en cours. On utilise getObject() parce que l'on ne connaît pas le type de la colonne de la table. loValeur = lrs.getObject(i); lsLigne = lsLigne + loValeur.toString() + "-"; 16 avril 2017 - Page 17 Java - JDBC 1.4.6 Alternative pour la récupération des valeurs Pour affiner le script précédent le type de chaque colonne du curseur est testé. En fonction du type de la colonne la fonction getXXX() appropriée est sollicitée. 1.4.6.1 Script while(lrs.next()) { lsLigne = ""; for(i=1; i<=liCols; i++) { switch(lrsmd.getColumnType(i)) { case Types.VARCHAR: lsLigne += lrs.getString(i) + "-"; break; case Types.CHAR: lsLigne += lrs.getString(i) + "-"; break; case Types.INTEGER: lsLigne += lrs.getInt(i) + "-"; break; case Types.DOUBLE: lsLigne += lrs.getLong(i) + "-"; break; default: lsLigne += "Inconnu-"; } } System.out.println(lsLigne); } 1.4.6.2 Commentaires Dans ce cas on utilise la méthode getColumnType(position) pour ensuite récupérer la valeur avec une méthode de type getString() ou getInt(),… 16 avril 2017 - Page 18 Java - JDBC 1.5 LA METHODE EXECUTE() 1.5.1 Objectif Utiliser la méthode execute() qui permet d'exécuter n'importe quel type d'ordre SQL; aussi bien un Select qu'un Insert, qu'un Delete, qu'un Update. 1.5.2 Principes et démarche On utilise la méthode Execute lorsque l'on ne connaît pas la nature de l'ordre SQL qui sera passé en argument. La méthode renvoie un booléen qui a la valeur : True si l'ordre exécuté est un Select False si l'ordre exécuté est un ordre de mise à jour. Selon le résultat on ouvrira un curseur ou on fera un traitement de validation de mise à jour. 1.5.3 Méthodes utilisées Méthodes boolean = Statement.execute() ResultSet = Statement.getResultSet() Fonctionnalités Exécute un ordre SQL et renvoie un booléen Renvoie un curseur 1.5.4 Script lstSql = lcConnexion.createStatement(); lbStatut = lstSql.execute(lsSql); if(lbStatut) { System.out.println("Un Select a été exécuté"); gRs = lstSql.getResultSet(); while(gRs.next()) { lsLigne = gRs.getString(1) + "-" + gRs.getString(2); System.out.println(lsLigne); } } else { System.out.println("Un ordre de mise à jour a été exécuté"); lcConnexion.commit(); } 16 avril 2017 - Page 19 Java - JDBC 1.5.5 Commentaires La méthode Execute est une méthode de l'interface Statement. Elle a pour paramètre un ordre SQL. Elle renvoie un booléen. lbStatut = lstSql.execute(lsSql); Si la méthode renvoie true on récupère le curseur grâce à la méthode getResultSet(). gRs = lstSql.getResultSet(); et on parcourt le curseur comme n'importe quel curseur. Si la méthode renvoie false on valide définitivement. 16 avril 2017 - Page 20 Java - JDBC 1.6 1.6.1 SQL DYNAMIQUE (PREPARE) Principe et démarche A côté de l'interface Statement il existe l'interface PreparedStatement qui permet d'exécuter un ordre SQL paramétré (aussi bien un SELECT qu'un ordre de MAJ). Ceci est indiqué dans deux cas : la requête est plusieurs fois exécutée, la requête envoie des caractères à échapper (', …). 1.6.2 Exemples String lsSql = "SELECT * FROM villes WHERE cp = ?"; PreparedStatement pst = cn.prepareStatement(lsSql); // --- Valorisation du ou des paramètre(s) pst.setString(1, "75011"); // Les valeurs pourraient être saisies au clavier // --- Exécution de la requête ResultSet rs = pst.executeQuery(); rs.next(); System.out.println(rs.getString("cp") + "-" + rs.getString("nom_ville")); String lsSql = "SELECT * FROM villes WHERE cp LIKE ?"; PreparedStatement pst = cn.prepareStatement(lsSql); pst.setString(1, "75%"); ResultSet rs = pst.executeQuery(); while(rs.next()) { System.out.println(rs.getString("cp") + "-" + rs.getString("nom_ville")); } String lsSql = "INSERT INTO villes(cp, nom_ville) VALUES(?,?)"; PreparedStatement pst = cn.prepareStatement(lsSql); pst.setString(1, "75999"); pst.setString(2, "Paris 999"); pst.executeUpdate(); 16 avril 2017 - Page 21 Java - JDBC 1.7 EXECUTER UNE PROCEDURE STOCKEE AVEC DES PARAMETRES IN 1.7.1 Objectif Exécuter une procédure stockée. Utiliser l'interface PreparedStatement. Remarques PreparedStatement pour les procédures stockées IN avec Connection.prepareStatement. CallableStatement pour les procédures stockées IN/OUT avec Connection.prepareCall. 1.7.2 Principes et démarche Créer une procédure stockée si besoin est. Créer un PreparedStatement et préparer l'appel. Appeler la procédure stockée. 1.7.3 Méthodes utilisées Méthodes PreparedStatement = Connection.prepareStatement(String lsCall) Fonctionnalités Crée un PreparedStatement PreparedStatement.executeQuery() PreparedStatement.executeUpdate() PreparedStatement.execute() Exécute l'ordre d'appel (SQL SELECT) Exécute l'ordre d'appel (SQL Maj) Exécute l'ordre d'appel (SQL SELECT ou Maj) 16 avril 2017 - Page 22 Java - JDBC 1.7.4 La procédure stockée Oracle Cette procédure stockée permet d'insérer un enregistrement dans la table Villes. CREATE OR REPLACE PROCEDURE VILLESINSERT(asCp IN villes.cp%type , asNomVille IN villes.nom_ville%type) IS BEGIN INSERT INTO villes(cp, nom) VALUES(asCp, asNomVille); COMMIT; END; / -- TEST sous SQL+ EXEC villesinsert('14000','Caen'); 1.7.5 La procédure stockée MySQL Cette procédure stockée permet d'insérer un enregistrement dans la table Villes. DELIMITER $$ DROP PROCEDURE IF EXISTS villesInsert $$ CREATE DEFINER=root@localhost PROCEDURE villesInsert(IN as_cp CHAR(5), IN as_ville CHAR(50), IN as_id_pays CHAR(3)) BEGIN INSERT INTO VILLES(cp, nom_ville, id_pays) VALUES(as_cp, as_ville, as_id_pays); COMMIT; END $$ DELIMITER ; -- Test sous MySQL Query Browser CALL villesInsert('14000','Caen','033'); 16 avril 2017 - Page 23 Java - JDBC 1.7.6 Script pour MySQL package packageSQL; import java.sql.*; public class VillesAjoutViaPs { public static void main(String[] args) { // --- Déclarations Connection lcConnexion = null; PreparedStatement lpstSql = null; String lsPilote = ""; String lsConnexion = ""; String lsUt = "root"; String lsMdp = ""; String lsCp = "14000"; String lsNomVille = "Caen"; String lsIdPays = "033"; String lsSQL = "{CALL villesInsert(?,?,?)}";; // --- Pour une connexion MySQL native lsPilote = "org.gjt.mm.mysql.Driver"; lsConnexion = "jdbc:mysql://localhost/cours"; try { Class.forName(lsPilote); lcConnexion = DriverManager.getConnection(lsConnexion,lsUt,lsMdp); lpstSql = lcConnexion.prepareStatement(lsSQL); lpstSql.setString(1,lsCp); lpstSql.setString(2,lsNomVille); lpstSql.setString(3,lsIdPays); int liR = lpstSql.executeUpdate(); System.out.println("Un Insert a été exécuté : " + liR); lpstSql.close(); lcConnexion.close(); lpstSql = null; lcConnexion = null; } catch(ClassNotFoundException err) { System.err.println(err.getMessage()); } catch(SQLException err) { System.err.println(err.getMessage()); } } } Notes St.execute() pour un ordre SQL quelconque (Renvoie un booléen). St.executeQuery() pour un ordre SELECT (Renvoie un Resultset). St.executeUpdate() pour un ordre de mise à jour (Renvoie un int). 1.7.7 Script pour Oracle // --- IDEM sauf la connexion 16 avril 2017 - Page 24 Java - JDBC 1.7.8 Commentaires 1.7.8.1 La déclaration de l'objet PreparedStatement En premier lieu il faut déclarer une variable de type interface PreparedStatement. PreparedStatement lpstSql; 1.7.8.2 La préparation de l'ordre d'appel L'appel de la procédure stockée se fera avec un CALL nomDeLaProcédure; La syntaxe est la suivante : "{CALL nomDeLaProcédure(paramètre 1[, paramètre 2]) }" lsSql = "{CALL villesinsert(?,?)}"; Il faut créer un objet de type PreparedStatement avec la méthode prepareStatement() de l'objet Connection en lui passant comme paramètre la chaîne de caractères précédente. lpstSql = lcConnexion.prepareStatement(lsSql); 1.7.8.3 L'appel de la procédure stockée Il faut ensuite demander l'exécution de l'ordre qui appelle la procédure stockée avec la méthode executeUpdate() de l'objet CallableStatement. lpstSql.executeUpdate(); 16 avril 2017 - Page 25 Java - JDBC 1.8 EXECUTER UNE PROCEDURE STOCKEE QUI RENVOIE UN SELECT La procédure MySQL DELIMITER $$ DROP PROCEDURE IF EXISTS villesSelect $$ CREATE PROCEDURE villesSelect() BEGIN SELECT * FROM villes; END $$ DELIMITER; -- Test sous MySQL Query Browser CALL villesSelect(); La procédure Oracle 16 avril 2017 - Page 26 Java - JDBC Le code java package packageSQL; import java.sql.*; import packageBD.BD; // ----------------------public class PsSelectMySQL // ----------------------{ public static void main(String[] args) { BD bd = new BD(); bd.seConnecter("cours", "root", "", "mysql"); try { Connection cn = bd.getConnexion(); PreparedStatement lpst = cn.prepareStatement("{CALL villesSelect()}"); ResultSet lrs = lpst.executeQuery(); while(lrs.next()) { System.out.println(lrs.getString(1)); } } catch(Exception e) { System.out.println(e.getMessage()); } bd.seDeconnecter(); } } 16 avril 2017 - Page 27 Java - JDBC 1.9 EXECUTER UNE PROCEDURE STOCKEE AVEC DES PARAMETRES OUT 1.9.1 Objectif Exécuter une procédure stockée avec des paramètres OUT. Voir les particularités de l'utilisation des paramètres OUT. Utiliser l'interface CallableStatement. 1.9.2 Principes et démarche Créer la procédure stockée Oracle ou autre. Déclarer un CallableStatement et préparer l'appel avec un PrepareCall(). Déclarer les paramètres et affecter des valeurs aux paramètres IN. Appeler la procédure stockée avec un execute(). Récupérer les valeurs des paramètres OUT. 1.9.3 Méthodes utilisées Méthodes Connection.prepareCall() CallableStatement.registerOutParameter(position, type) CallableStatement.execute() CallableStatement.setString(rang, valeur) CallableStatement.getString(rang) 16 avril 2017 - Page 28 Fonctionnalités Crée un CallableStatement Précise la position et le type du retour des paramètres Exécute l'ordre d'appel Affecte une valeur à un paramètre Récupère une valeur d'un paramètre Java - JDBC 1.9.4 La procédure stockée Oracle Cette procédure stockée Oracle permet d'insérer une ville dans la table [villes] et de récupérer le code d'erreur et le message d'erreur du SGBD. CREATE OR REPLACE PROCEDURE VILLESINSERTOUT( asCp in villes.cp%type, asNomVille in villes.nom_ville%type, aiCodeErreur out NUMBER, asTexteErreur out VARCHAR2) IS vide EXCEPTION; BEGIN IF asCp IS NULL THEN RAISE Vide; END IF; IF asNomVille IS NULL THEN RAISE Vide; END IF; INSERT INTO villes(cp,nom_ville) VALUES(asCp,asNomVille); COMMIT; aiCodeErreur := 0; asTexteErreur := 'OK'; EXCEPTION WHEN Vide THEN aiCodeErreur := -1; asTexteErreur := 'vide'; WHEN OTHERS THEN aiCodeErreur := SQLCODE; asTexteErreur := SUBSTR(SQLERRM,1,100); END; / -- Test sous SQL*PLUS SET SERVER OUTPUT ON DECLARE liCode NUMBER(10); lsMsg VARCHAR2(100); BEGIN villesinsertout('14000','Caen', liCode, lsMsg); dbms_output.put_line('Err : ' || liCode || ' msg : ' || lsMsg); END; / 16 avril 2017 - Page 29 Java - JDBC 1.9.5 Script package packageSQL; import java.sql.*; // ---------------------public class ProcStockOut // ---------------------{ public static void main(String[] args) { // --- Déclarations Connection lcConnexion = null; CallableStatement lcstSql = null; String lsConnexion; String lsSql = null; String lsUt = "p"; String lsMdp = "b"; String lsMsgErreur = null; double ldCodeErreur; try { Class.forName("oracle.jdbc.driver.OracleDriver"); lsConnexion = "jdbc:oracle:thin:@140.0.0.68:1521:orac"; lcConnexion = DriverManager.getConnection(lsConnexion,lsUt,lsMdp); // --- Les paramètres out doivent être en premier autrement tous en ? pour pouvoir de toutes façons dynamiser l'appel lsSql = "{CALL villesinsertout(?,?,?,?)}"; lcstSql = lcConnexion.prepareCall(lsSql); lcstSql.setString(1,"14000"); lcstSql.setString(2,"Caen"); lcstSql.registerOutParameter(3,Types.NUMERIC); lcstSql.registerOutParameter(4,Types.VARCHAR); lcstSql.execute(); ldCodeErreur = lcstSql.getLong(3); lsMsgErreur = lcstSql.getString(4); System.out.println("Message d'erreur BD : " + lsMsgErreur); System.out.println("Code d'erreur BD : " + ldCodeErreur); lcstSql.close(); lcConnexion.close(); lcstSql = null; lcConnexion = null; } catch(ClassNotFoundException err) { System.err.println(err.getMessage()); } catch(SQLException err) { System.err.println(err.getMessage()); } } } 16 avril 2017 - Page 30 Java - JDBC 1.9.6 Commentaires 1.9.6.1 La préparation de l'appel Pour dynamiser l'appel vous faites un appel paramétré avec autant de ? qu'il y a de paramètres. lsSql = "{CALL villesinsert2(?,?,?,?)}"; Vous préparez l'appel : lcstSql = lcConnexion.prepareCall(lsSql); Vous affectez des valeurs aux paramètres IN avec la méthode setString(rang, valeur) ou setXXX(rang, valeur) applicable à l'objet CallableStatement. Vous déclarez les paramètres OUT au moyen de la méthode registerOutParameter(rang, type). lcstSql.setString(1,"14000"); lcstSql.registerOutParameter(3,Types.NUMERIC); 1.9.6.2 L'appel via la méthode execute() lcstSql.execute(); 1.9.6.3 La récupération des résultats Vous récupérez les valeurs des paramètres OUT avec une méthode getXXX() appliquée à l'objet CallableStatement. ldCodeErreur = lcstSql.getLong(3); lsMsgErreur = lcstSql.getString(4); 16 avril 2017 - Page 31 Java - JDBC 1.10 EXECUTER UNE FONCTION STOCKEE 1.10.1 Objectif Utiliser une fonction stockée à partir d'une application JAVA. 1.10.2 Principes et démarche Le principe est le même que pour les procédures stockées mis à part que le résultat (Out) est le premier "paramètre". 1.10.3 Méthodes utilisées Méthodes Connection.prepareCall() CallableStatement.registerOutParameter(position, type) CallableStatement.execute() CallableStatement.setString(rang, valeur) CallableStatement.getString(rang) 16 avril 2017 - Page 32 Fonctionnalités Crée un CallableStatement Précise la position et le type du retour Exécute l'ordre d'appel Affecte une valeur à un paramètre Récupère une valeur d'un paramètre Java - JDBC 1.10.4 La fonction stockée Oracle Cette fonction stockée Oracle insère un enregistrement dans la table Villes. Elle possède deux paramètres en entrée et le retour (de type Varchar2) qui renvoie Ok ou le message d'erreur. CREATE OR REPLACE FUNCTION VILLESINSERTFCT(asCp IN villes.cp%type , asNomVille IN villes.nom_ville%type) RETURN VARCHAR2 IS lsMsg VARCHAR2(100); BEGIN INSERT INTO villes(cp, nom_ville) VALUES(asCp, asNomVille); COMMIT; RETURN 'OK'; EXCEPTION WHEN dup_val_on_index THEN lsMsg := SUBSTR(sqlerrm(sqlcode),1,100); RETURN lsMsg; WHEN OTHERS THEN lsMsg := SUBSTR(sqlerrm(sqlcode),1,100); RETURN lsMsg; END; / -- TEST sous SQL SET SERVEROUTPUT ON DECLARE lsMsg VARCHAR2(100); BEGIN lsMsg := VILLESINSERTFCT('75021','Paris 21'); dbms_output.put_line('Résultat : ' || lsMsg); END; / 1.10.5 La fonction stockée MySQL DELIMITER $$ DROP FUNCTION IF EXISTS villesInsertFct $$ CREATE FUNCTION villesInsertFct(asCp VARCHAR(5), asNomVille VARCHAR(50), asIdPays VARCHAR(3)) RETURNS VARCHAR(255) BEGIN INSERT INTO villes(cp, nom_ville, id_pays) VALUES(asCp, asNomVille, asIdPays); RETURN 'OK'; END $$ DELIMITER ; -- Test sous MySQL Query Browser SELECT villesInsertFct('71000','Tournus','033'); 16 avril 2017 - Page 33 Java - JDBC 1.10.6 Script String lsSql = "{? = CALL villesinsertfct(?,?)}"; CallableStatement lcstSql = null; lcstSql = lcConnexion.prepareCall(lsSql); lcstSql.registerOutParameter(1,Types.VARCHAR); lcstSql.execute(); System.out.println(lcstSql.getString(1)); 16 avril 2017 - Page 34 Java - JDBC 1.10.7 Commentaires 1.10.7.1 Création de la chaîne d'appel La chaîne d'appel a le format suivant : "{? = call nomDeLaFonction( paramètres) }" lsSql = "{? = CALL villesinsertfct('14000','Caen')}"; 1.10.7.2 Création du callableStatement Utilisation de la méthode prepareCall() de l'objet Connection en passant comme paramètre la chaîne d'appel. lcstSql = lcConnexion.prepareCall(lsSql); 1.10.7.3 Précision du type de retour Il faut préciser de quel type est le retour de la fonction (String, int,…) avec la méthode registerOutParameter() de l'objet CallableStatement qui possède deux paramètres : la position et le type. La position pour le retour d'une fonction est toujours 1. Le type correspond aux types SQL définis dans l'API java.sql. lcstSql.registerOutParameter(1,Types.VARCHAR); 1.10.7.4 Appel de la fonction Comme pour une procédure stockée on invoque la méthode execute() de l'objet CallableStatement. lcstSql.execute(); 1.10.7.5 Récupération du résultat Selon le type du résultat on utilise la méthode getXXX() adéquate. lsResultat = lcstSql.getString(1); 16 avril 2017 - Page 35 Java - JDBC 1.11 ACCES A LA METABASE 1.11.1 Objectif et démarche Accéder aux informations de la Metabase : pilote, url, bds, tables, colonnes, clés primaires, … Utiliser les méthodes de la classe DatabaseMetadata. 1.11.2 Quelques méthodes Méthode cn.getMetaData() Fonctionnalité Renvoie un ResultsetMetadata md.getDriverName() md.getUserName() md.getURL() Renvoie le nom du pilote Renvoie le nom de l'utilisateur connecté md.getCatalogs() md.getTables() md.getColumns() Renvoie la liste des BD d'un serveur Renvoie la liste des tables d'une BD Renvoie la liste des colonnes d'une table Renvoie l'URL de la base (jdbc:odbc:dsn_…) Il en existe une trentaine d'autres. Exemple de résultat attendu avec MySQL : Editeur de la base : MySQL Driver : JDBC-ODBC Bridge (myodbc3.dll) URL JDBC : jdbc:odbc:dsn_mysql_cours Ut : root BDs : information_schema,___ajax_bd,cours,cqrsa,elections,exos_sql,forum,immobilier,libra irie,locations_films,mysql,nouvelle,pariscope,portail_infos,test,unilog, Tables de librairie : clients(TABLE),commandes(TABLE),cours_livres(TABLE), Colonnes de Villes : cp(varchar),nom_ville(varchar),photo(varchar),site(varchar), Notes Avec Oracle getCatalogs() ne renvoie rien donc getTables() et getColumns() non plus. Donc il faut utiliser des curseurs et des SELECT sur la metabase (SELECT * FROM cat WHERE …, SELECT * FROM user_tables WHERE …). 16 avril 2017 - Page 36 Java - JDBC 1.11.3 Script import java.sql.*; public class MetaData { public static void main(String[] args) { Connection lcn = null; DatabaseMetaData ldbmd = null; ResultSet lrsCatalogues = null; ResultSet lrsTables = null; ResultSet lrsCols = null; String lsInfos = ""; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); lcn = DriverManager.getConnection("jdbc:odbc:dsn","ut","mdp"); // --- Accès à la métabase, au dictionnaire ldbmd = lcn.getMetaData(); lsInfos += "\nEditeur de la base : " + ldbmd.getDatabaseProductName(); lsInfos += "\nDriver : " + ldbmd.getDriverName(); lsInfos += "\nURL JDBC : " + ldbmd.getURL(); lsInfos += "\nUt : " + ldbmd.getUserName(); lsInfos += "\nBDs : "; lrsCatalogues = ldbmd.getCatalogs(); while(lrsCatalogues.next()) lsInfos += lrsCatalogues.getString(1) + ","; lsInfos += "\nTables : "; String tTypes[] = null; // --getTables("Catalogue","SchemaPattern","TablePattern",tableTypes) // --- SchemaPattern : ??? // --- Exemple : les tables de la bd dont le nom commence par C tous types confondus. // --- TableType : Tables, Views, Synonyms, … // --- Le RS a cette structure (cat, tableSchema, tableName, tableType, ...) lrsTables = ldbmd.getTables("librairie", "", "C",tTypes); while(lrsTables.next()) lsInfos += lrsTables.getString(3) + "(" + lrsTables.getString(4) + "),"; lsInfos += "\nColonnes de Villes : "; // --getColumns("Catalogue","SchemaPattern","TablePattern","ColumnPattern") // --- SchemaPattern : ??? // --- Exemple : les colonnes de la table villes de la bd librairie. // --- TableType : Tables, Views, Synonyms,.. // --- Le RS a cette structure (cat, tableSchema, tableName, columnName, ...) lrsCols = ldbmd.getColumns("librairie", "", "Villes", ""); while(lrsCols.next()) lsInfos += lrsCols.getString(4) + "(" + lrsCols.getString(6) + "),"; System.out.println(lsInfos); lcn.close(); } catch(Exception erreur) { System.err.println(erreur); } } } 16 avril 2017 - Page 37 Java - JDBC 1.12 UN CURSEUR "SCROLLABLE" Pour scroller un curseur il faut, lors de sa création, le définir comme "scrollable". createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); Cf les annexes pour les détails du paramétrage. Il faut aussi que le pilote le permette. Les méthodes previous(), first() et last() sont alors applicables en plus de la méthode next(). import java.sql.*; public class CurseurScrollable { public static void main(String[] args) { // --- Pour une connexion avec un pilote natif oracle String lsPilote = "oracle.jdbc.driver.OracleDriver"; String lsConnexion = "jdbc:oracle:thin:@localhost:1521:xe"; String lsSelect = "SELECT * FROM villes"; try { Class.forName(lsPilote); Connection lcConnexion = DriverManager.getConnection(lsConnexion,"p","b"); Statement lstSql = lcConnexion.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet lrs = lstSql.executeQuery(lsSelect); while(lrs.next()) { System.out.println(lrs.getString(1) + "-" + lrs.getString(2)); } //lrs.previous(); lrs.first(); System.out.println(lrs.getString(1) + "-" + lrs.getString(2)); lrs.close(); lstSql.close(); lcConnexion.close(); } catch(ClassNotFoundException err) { System.err.println(err.getMessage()); } catch(SQLException err) { System.err.println(err.getMessage()); } } } 16 avril 2017 - Page 38 Java - JDBC 1.13 UN CURSEUR "UPDATABLE" Un curseur "updatable" est un curseur au travers duquel il est possible de faire une mise à jour. Encore faut-il que le pilote le permette. Apparemment via le pilote natif Oracle c'est impossible, mais via ODBC une table Oracle est modifiable via un curseur. Les méthodes de curseur updateString() et updateRow() sont alors utilisables. Mais avec Oracle les résultats sont parfois inattendus sur les varchar2 !!! import java.sql.*; public class CurseurUpdatable { public static void main(String[] args) { // --- Pour une connexion avec un pilote natif oracle //String lsPilote = "oracle.jdbc.driver.OracleDriver"; //String lsConnexion = "jdbc:oracle:thin:@localhost:1521:xe"; // --- Connexion ODBC String lsPilote = "sun.jdbc.odbc.JdbcOdbcDriver"; String lsConnexion = "jdbc:odbc:dsn_oracle_xe"; String lsSelect = "SELECT * FROM villes"; try { Class.forName(lsPilote); Connection lcConnexion = DriverManager.getConnection(lsConnexion,"p","b"); Statement lstSql = lcConnexion.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet lrs = lstSql.executeQuery(lsSelect); while(lrs.next()) { System.out.println(lrs.getString(1) + "-" + lrs.getString(2)); if(lrs.getString(1).equals("75011")) { lrs.updateString(2,"Paris XI"); lrs.updateRow(); } } lrs.close(); lstSql.close(); lcConnexion.close(); } catch(ClassNotFoundException err) { System.err.println(err.getMessage()); } catch(SQLException err) { System.err.println(err.getMessage()); } } } 16 avril 2017 - Page 39 Java - JDBC CHAPITRE 2 - ANNEXES 16 avril 2017 - Page 40 Java - JDBC 2.1 UNE SEULE CLASSE POUR LA GESTION BD 2.1.1 Objectif Créer une classe de "services" pour manipuler n'importe quelle table d'une BD. Les méthodes plus en détail Méthode StringBuilder seConnecter(String asBd, String asUt, String asMdp) StringBuilder seConnecter(String asBd, String asUt, String asMdp, String asPilote) boolean seDeconnecter() Connection getConnexion() ResultSet getCurseur(String asSelect) ResultSet getCurseur(String asSelect, int aiScroll, int aiLecture) StringBuilder getCurseurCSV(String asSelect) Vector getCurseur1D(String asSelect) TreeMap getCurseur2D(String asSelect) int supprimer(String asTable, String asColonne, String asValeur) int inserer(String asTable, String[] asColonnes, String[] asValeurs) int inserer(String asTable, String asColonnes, String asValeurs) String executerPs(String asProcedure, String asValeurs) String valider() String annuler() … 16 avril 2017 - Page 41 Description Java - JDBC 2.1.2 Exemple 75012;Paris 12 75011;Paris 11 24200;Sarlat 14000;Caen package packageBD; // ---------------public class BdTest // ---------------{ public static void main(String[] args) { BD bd = new BD(); StringBuilder lsb = bd.seConnecter(); if(lsb.toString().equals("OK")) { System.out.println(bd.getCurseurCSV("SELECT * FROM villes")); System.out.println(bd.seDeconnecter()); } else System.out.println(lsb.toString()); } } 2.1.3 Code de la classe Code dans le fichier BD.java. 16 avril 2017 - Page 42 Java - JDBC 2.2 QUELQUES METHODES POUR LA MANIPULATION DES BD 2.2.1 Class.forName Objectif La méthode forName de la classe Class permet de définir le pilote utilisé. Que le pilote soit natif ou qu'il utilise ODBC. Syntaxe Class.forName("Nom_du_pilote") Exemples Class.forName("oracle.jdbc.driver.OracleDriver"); // --- Pilote natif Oracle Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // --- Pilote JDBC-ODBC Class.forName("org.gjt.mm.mysql.Driver"); // --- Pilote natif MySQL 2.2.2 DriverManager.getConnection Objectif Se connecter. La méthode getConnection() de la classe DriverManager permet de tenter de se connecter. Cette méthode renvoie un booléen. L'adresse de la BD est composée comme une URL. Syntaxe Connection = DriverManager.getConnection(urlBD, utilisateur, motDePasse) Exemples cn = DriverManager.getConnection("jdbc:oracle:@140.0.0.68:1521:orac","p","b"); cn = DriverManager.getConnection("jdbc:odbc:dsn_oracle","p","b"); cn = DriverManager.getConnection("jdbc:mysql://localhost/cours","root",""); 16 avril 2017 - Page 43 Java - JDBC 2.2.3 Connection.close Objectif La méthode close de la classe Connection permet de fermer une connexion. Syntaxe Connection.close() Exemples cn.close(); 2.2.4 createStatement Objectif La méthode createStatement de la classe Connection permet de définir un objet pour l'exécution de commandes SQL. Cette méthode renvoie un objet de type statement. Syntaxe statement = Connection.createStatement([Sens, Lecture/Ecriture]) Sens : ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE Lecture/Ecriture : ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE Exemples gInstruction = cn.createStatement(); gInstruction = cn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); gInstruction = cn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); 16 avril 2017 - Page 44 Java - JDBC 2.2.5 executeQuery Objectif La méthode executeQuery() de la classe Statement permet d'exécuter une requête de type SELECT. Cette méthode renvoie un objet de type RecordSet. Syntaxe RecordSet = Statement.executeQuery("OrdreSQLSelect") Exemple gRs = gInstruction.executeQuery("SELECT * FROM villes"); Remarques La méthode executeUpdate("ordreSQL") exécute un ordre SQL de mise à jour. Elle renvoie un int. La méthode execute("ordreSQL") exécute un ordre SQL. Elle renvoie un booléen (true si c'est un SELECT et false si c'est un ordre CUD). 16 avril 2017 - Page 45 Java - JDBC 2.2.6 Tableaux des Classes et Interfaces 2.2.6.1 La classe java.sql.DriverManager Méthodes Connection = DriverManager.getConnection("url") Connection = DriverManager.getConnection("url", "login", "pwd") Fonctionnalités Permet de se connecter idem 2.2.6.2 L'interface java.sql.Connection Méthodes Connection.close() Booléen = conection.isClosed() Statement = connection.createStatement() Statement = connection.createStatement(type_result_set, acces_concurrent) PreparedStatement = connection.preparedStatement("sql") PreparedStatement = connection.preparedStatement("sql", type_result_set, acces_concurrent) CallableStatement = connection.prepareCall("sql") CallableStatement = connection.prepareCall("sql", type_result_set, acces_concurrent) DatabaseMetatData = connection.getMetaData() Connection.setAutoCommit(booléen) Booléen = connection.getAutoCommit() Connection.commit() Connection.rollback() Connection.setTransactionIsolation(niveau) Int = Connection.getTransactionIsolation() Connection.setReadOnly(booléen) Booléen = connection.isReadOnly() SQLWarnings = Connection.getWarnings() Connection.clearWarnings() Connection.setCatalog("catalogue") String = Connection.getCatalog() Map = connection.getTypeMap() Connection.setTypeMap(map) (*) resultSetType : ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE resultSetConcurrency : ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE 16 avril 2017 - Page 46 Fonctionnalités Permet de se déconnecter Tester l'état de la connexion Créer une instruction Idem (*) Prépare une requête compilée Idem Prépare une procédure stockée idem Récupérer des informations sur la métabase Modifier l'état de l'autocommit Récupèrer l'état de l'autocommit Valider la transaction Invalider la transaction Modifier le niveau d'isolation Récupérer le niveau d'isolation Modifier l'état RW de la bd Récupérer l'état RW Récupère les avertissements Supprime les avertissements Définir un catalogue Récupérer un catalogue Permettre de récupérer les mappages de types SQL-JAVA de la session Permettre de créer les mappages de types SQL-JAVA pendant une session Java - JDBC 2.2.6.3 L'interface java.sql.Statement Objet pour exécuter un ordre SQL statique et récupérer un curseur. Méthodes ResultSet executeQuery("SELECT SQL") Int executeUpdate("Ordre SQL") Booléen execute("OrdreSQL") Connection getConnection() ResultSet getResultSet() Void close() Fonctionnalités Idem pour un ordre Select Idem pour un ordre de MAJ Un ordre du LMD ou du LDD Récupère une connexion Récupère un curseur Ferme l'instruction et réinitialise 2.2.6.4 L'interface java.sql.PreparedStatement Objet qui représente un ordre SQL précompilé ou une procédure stockée IN (Hérite de Statement). Méthodes Void setXXX(index du paramètre, valeur) XXX getXXX(index du paramètre) Boolean execute("Ordre SQL") ResultSet executeQuery("Ordre SQL") Int executeUpdate("Ordre SQL") Fonctionnalités Affecte une valeur Récupère une valeur Exécute un ordre SQL Exécute un ordre Select Exécute un ordre de MAJ Cf l'objet connection et la méthode preparedStatement 2.2.6.5 L'interface java.sql.CallableStatement Interface pour exécuter une procédure stockée SQL OUT (Hérite de PreparedStatement). Méthodes Void setXXX(nom_du_paramètre, valeur) XXX getXXX(index du paramètre) Fonctionnalités Affecte une valeur Récupère une valeur Cf l'objet connection et la méthode prepareCall 16 avril 2017 - Page 47 Java - JDBC 2.2.6.6 L'interface java.sql.ResultSet Un curseur Méthodes Boolean Boolean Boolean Boolean first() previous() next() last() Déplace Déplace Déplace Déplace le le le le Boolean Boolean Boolean Boolean isFirst() isLast() isBeforeFirst() isAfterLast() Renvoie Renvoie Renvoie Renvoie vrai vrai vrai vrai Void Void Void Void insertRow() moveToInsertRow() deleteRow() updateRow() pointeur pointeur pointeur pointeur si si si si le le le le Fonctionnalités sur la première ligne sur la ligne précédente sur la ligne suivante sur la dernière ligne pointeur pointeur pointeur pointeur est est est est au début à la fin avant le début (BOF) après la fin (EOF) Insère une ligne Déplace le pointeur sur la nouvelle ligne Supprime une ligne Met à jour une ligne String getString(indexColonne) String getString("nomColonne") XXX = getXXX(indexColonne ou "nomColonne") Récupère la valeur d'une colonne Récupère la valeur d'une colonne Récupère la valeur d'une colonne (String, numérique,…) Void updateString("Champ", valeur) Void updateXXX("Champ", valeur) Met à jour la colonne de l'enregistrement courant Idem pour les autres types Void close() Boolean absolute(numero de ligne) Int getRow() Void refreshRow() Statement = getStatement() ResultSetMetaData = getMetaData() Ferme le curseur Déplace le pointeur sur la ligne Renvoie le numéro de la ligne courante Actualise la ligne Renvoie le statement Renvoie la structure du curseur 16 avril 2017 - Page 48 Java - JDBC 2.3 2.3.1 TRANSFERTS BD-FICHIER Bd2Fichier Objectif : transfert table BD vers fichier CSV. package packageSQL; import java.sql.*; import java.io.*; import packageBD.BD; // --------------------public class BdToFichier // --------------------{ // ----------------------------------public static void main(String[] args) // ----------------------------------{ // --- Déclarations Connection lcConnexion = null; String lsTable = "genres"; String lsSelect = ""; StringBuilder lsbSortie = new StringBuilder(""); FileWriter lfwFichier; try { BD bd = new BD(); bd.seConnecter(); lcConnexion = bd.getConnexion(); lfwFichier = new FileWriter(lsTable + ".csv"); lsSelect = "SELECT * FROM " + lsTable; lsbSortie = bd.getCurseurCSV(lsSelect); lfwFichier.write(lsbSortie.toString()); lfwFichier.flush(); lfwFichier.close(); lcConnexion.close(); lcConnexion = null; } catch(IOException err) { System.err.println("Erreur IO : " + err.getMessage()); } catch (SQLException err) { System.err.println("\nErreur SQL : " + err.getMessage()); } System.out.println("Création du fichier CSV réussie"); } } 16 avril 2017 - Page 49 Java - JDBC La méthode getCurseurCSV() de la classe BD. // ------------------------------public StringBuilder getCurseurCSV(String asSelect) // ------------------------------{ StringBuilder lsbResultat = new StringBuilder(""); ResultSet lrs = null; ResultSetMetaData lrsmd; // --- Objet structure de curseur // --- Récupération du contenu du curseur lrs = this.getCurseur(asSelect); try { // --- La structure du curseur lrsmd = lrs.getMetaData(); // --- Les en-têtes for(int i=1; i<=lrsmd.getColumnCount(); i++) { lsbResultat.append(lrsmd.getColumnName(i) + ";"); } lsbResultat.deleteCharAt(lsbResultat.length()-1); lsbResultat.append("\r\n"); while(lrs.next()) { for(int i=1; i<=lrsmd.getColumnCount(); i++) { lsbResultat.append(lrs.getString(i) + ";"); } lsbResultat.deleteCharAt(lsbResultat.length()-1); lsbResultat.append("\r\n"); } } catch(SQLException err) { lsbResultat.append(err.getMessage()); } return lsbResultat; } 16 avril 2017 - Page 50 Java - JDBC 2.3.2 Fichier2Bd Objectif : transférer un fichier dans une table d'une BD. package packageSQL; import java.sql.*; import java.io.*; import packageBD.BD; // --------------------public class FichierToBD // --------------------{ // ----------------------------------public static void main(String[] args) // ----------------------------------{ // --- Déclarations BD bd = new BD(); Connection lcConnexion; String lsColonnes = ""; String lsLigne = ""; FileReader lfrFichier; BufferedReader lbrBuffer; try { bd.seConnecter(); lcConnexion = bd.getConnexion(); // --- Le constructor(argument : nom du fichier) lfrFichier = new FileReader("genres.csv"); lbrBuffer = new BufferedReader(lfrFichier); lsColonnes = lbrBuffer.readLine(); lsColonnes = lsColonnes.replaceAll(";", ","); while((lsLigne = lbrBuffer.readLine()) != null) { lsLigne = lsLigne.replaceAll(";", "','"); lsLigne = "'" + lsLigne + "'"; System.out.println(bd.insererSimple("genres", lsColonnes, lsLigne)); } // --- La méthode close pour fermer le canal lfrFichier.close(); lcConnexion.close(); lcConnexion = null; } catch(FileNotFoundException err) { System.err.println(err.getMessage()); } catch(IOException err) { System.err.println(err.getMessage()); } catch (SQLException err) { System.err.println("\nErreur SQL"); System.err.println(err); } System.out.println("Transfert Fichier-BD terminé"); } } 16 avril 2017 - Page 51 Java - JDBC 2.4 2.4.1 LES PILOTES ODBC (Open DataBase Connectivity) Il faut au préalable créer un DSN. Le DSN 16 avril 2017 - Page 52 Java - JDBC Montage du pilote Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connexion lsConnexion = "jdbc:odbc:dsn_oracle_xe"; Connection cn = DriverManager.getConnection(lsConnexion, lsUt, lsMdp); 16 avril 2017 - Page 53 Java - JDBC 2.4.2 JDBC-MySQL Correspond à mysql-connector-java-5.1.12-bin.jar (Type 4 : natif, direct). Bibliothèque à ajouter au projet. Procédure Téléchargez mysql-connector-java-5.1.12 chez MySQL AB. Décompactez-le. Copiez le fichier mysql-connector-java-5.1.12-bin.jar dans un dossier. Ajoutez ce jar au projet. Sous NetBeans Montage du pilote Class.forName("org.gjt.mm.mysql.Driver"); Connexion Protocole:sous-protocole://hôte/bd String lsConnexion = "jdbc:mysql://localhost/cours"; Connection cn = DriverManager.getConnection(lsConnexion, lsUt, lsMdp); 16 avril 2017 - Page 54 Java - JDBC 2.4.3 JDBC-Oracle (Java DataBase Connectivity) Cette configuration ne nécessite pas, côté client, de fonctionnalité Middleware OracleNET. D'abord télécharger le package Oracle pour le pilote : pour le JDK 1.4 et supérieur c'est le jar suivant : ojdbc14.jar Et ensuite l'inclure dans la liste des bibliothèques utilisées. Sous NetBeans Montage du pilote Class.forName("oracle.jdbc.driver.OracleDriver"); Connexion lsConnexion = "jdbc:oracle:thin:@localhost:1521:xe"; Connection cn = DriverManager.getConnection(lsConnexion, lsUt, lsMdp); 16 avril 2017 - Page 55 Java - JDBC 2.5 2.5.1 LE PATTERN DAO ET LES BEANS Le modèle Ce modèle (donc ces classes : Villes.java et VillesDao.java) sera réutilisé avec SWING, les servlets et JSP … Le modèle DAO et les beans sont utilisés dans le cadre du modèle MVC (Modèle, Vue, Contrôleur). Le modèle MVC a pour objectif de modéliser en couches. Les interfaces pour les vues, les données pour le Modèle et le contrôleur pour la gestion des appels, des flux de l'application. 16 avril 2017 - Page 56 Java - JDBC 2.5.2 Le JavaBean 2.5.2.1 Définition Un JavaBean est une classe qui représente une ressource stockée (table, fichier, …). Il est composé de propriétés, de getters et de setters et souvent d'un constructeur vide. C'est une classe sérialisable. C'est le standard de Sun. Pour plus de détails cf le support java_jsp.doc. 2.5.2.2 Exemple : le JavaBean Villes La structure de la table Villes(cp, nom_ville, site, photo, id_pays). package packageBD; import java.io.Serializable; import java.util.ArrayList; // --- Le JavaBean -----------------------public class Villes implements Serializable // ---------------------------------------{ // --- Les attributs private String cp; private String nomVille; private String site; private String photo; private String idPays; VillesDAO dao = null; // --- Le constructeur public Villes() { this.dao = new VillesDAO(); } // --- Les méthodes accédant au DAO public String inserer() { return this.dao.inserer(this); } public String supprimer() { return this.dao.supprimer(this.cp); } public String modifier() { return this.dao.modifier(this); } public void selectUn(String cp) { Villes ville = this.dao.selectUn(cp); this.cp = ville.cp; this.nomVille = ville.nomVille; this.site = ville.site; this.photo = ville.photo; this.idPays = ville.idPays; } 16 avril 2017 - Page 57 Java - JDBC public ArrayList selectTous() { return dao.selectTous(); } // --- Les getters et setters public String getCp() { return cp; } public void setCp(String cp) { this.cp = cp; } public String getIdPays() { return idPays; } public void setIdPays(String idPays) { this.idPays = idPays; } public String getNomVille() { return nomVille; } public void setNomVille(String nomVille) { this.nomVille = nomVille; } public String getPhoto() { return photo; } public void setPhoto(String photo) { this.photo = photo; } public String getSite() { return site; } public void setSite(String site) { this.site = site; } } 16 avril 2017 - Page 58 Java - JDBC 2.5.3 Le DAO 2.5.3.1 Définition Le DAO (Data Access Objet) est un modèle d'accès aux données. Il implémente le CRUD. En principe les classes DAO implémentent une interface IDAO. Les méthodes sont les suivantes : Insérer avec en argument un objet. Supprimer avec en argument une clé. Modifier avec en argument un objet. SelectUn avec en argument une clé et en retour un objet. SelectTous avec en retour une liste d'objets. 16 avril 2017 - Page 59 Java - JDBC 2.5.3.2 Exemple : le DAO VillesDAO Le DAO package packageBD; import java.sql.*; import java.util.*; // ------------------public class VillesDAO // ------------------{ private Connection cn; // --------------public VillesDAO() { try { Class.forName("org.gjt.mm.mysql.Driver"); this.cn = DriverManager.getConnection("jdbc:mysql://localhost/cours","root",""); } catch(ClassNotFoundException err) { System.err.println(err.getMessage()); } catch(SQLException err) { System.err.println(err.getMessage()); } } // -------------------------------public String inserer(Villes ville) { String lsMessage = ""; String lsInsert = "INSERT INTO villes(cp,nom_ville,site,photo,id_pays) VALUES(?,?,?,?,?)"; try { PreparedStatement pst = this.cn.prepareStatement(lsInsert); pst.setString(1, ville.getCp()); pst.setString(2, ville.getNomVille()); pst.setString(3, ville.getSite()); pst.setString(4, ville.getPhoto()); pst.setString(5, ville.getIdPays()); pst.executeUpdate(); lsMessage = "Insertion OK"; } catch(SQLException e) { lsMessage = e.getMessage(); } return lsMessage; } // ------------------------------public String supprimer(String cp) { String lsMessage = ""; String lsDelete = "DELETE FROM villes WHERE cp=?"; try { PreparedStatement pst = this.cn.prepareStatement(lsDelete); pst.setString(1, cp); pst.executeUpdate(); lsMessage = "Suppression OK"; } 16 avril 2017 - Page 60 Java - JDBC catch(SQLException e) { lsMessage = e.getMessage(); } return lsMessage; } // --------------------------------public String modifier(Villes ville) { String lsMessage = ""; String lsUpdate = "UPDATE villes SET nom_ville=?, photo=? WHERE cp=?"; try { PreparedStatement pst = this.cn.prepareStatement(lsUpdate); pst.setString(1, ville.getNomVille()); pst.setString(2, ville.getPhoto()); pst.setString(3, ville.getCp()); pst.executeUpdate(); lsMessage = "Modification OK"; } catch(SQLException e) { lsMessage = e.getMessage(); } return lsMessage; } // -----------------------------public Villes selectUn(String cp) { Villes uneVille = new Villes(); String lsSelect = "SELECT * FROM villes WHERE cp=?"; try { PreparedStatement pst = this.cn.prepareStatement(lsSelect); pst.setString(1, cp); ResultSet rs = pst.executeQuery(); rs.next(); uneVille.setCp(rs.getString(1)); uneVille.setNomVille(rs.getString(2)); uneVille.setSite(rs.getString(3)); uneVille.setPhoto(rs.getString(4)); uneVille.setIdPays(rs.getString(5)); } catch(SQLException e) { } return uneVille; } // -------------------------public ArrayList selectTous() { ArrayList tVilles = new ArrayList(); String lsSelect = "SELECT * FROM villes"; try { PreparedStatement pst = this.cn.prepareStatement(lsSelect); ResultSet rs = pst.executeQuery(); while(rs.next()) { Villes uneVille = new Villes(); uneVille.setCp(rs.getString(1)); uneVille.setNomVille(rs.getString(2)); uneVille.setSite(rs.getString(3)); uneVille.setPhoto(rs.getString(4)); uneVille.setIdPays(rs.getString(5)); tVilles.add(uneVille); 16 avril 2017 - Page 61 Java - JDBC } } catch(SQLException e) { } return tVilles; } } 16 avril 2017 - Page 62 Java - JDBC TEST DAO package packageBD; import java.util.ArrayList; public class VillesDAOTest { public static void main(String[] args) { // --Villes ville = new Villes(); ArrayList tVilles = new ArrayList(); // --- Remplissage du Bean ville.setCp("75021"); ville.setNomVille("Paris XXI"); ville.setSite("www.paris21.fr"); ville.setPhoto("parisXXI.jpg"); ville.setIdPays("033"); // // // // // // --- Insertion via le Bean //System.out.println(ville.inserer()); // --- Suppression via le Bean //System.out.println(ville.supprimer()); // // // --- Modification via le Bean ville.modifier(); System.out.println(ville.getNomVille()); // // // // // // // --- Visu UN via le bean ville.selectUn("75012"); System.out.println(ville.getCp()); System.out.println(ville.getNomVille()); System.out.println(ville.getSite()); System.out.println(ville.getPhoto()); System.out.println(ville.getIdPays()); // --- Visu Tous via le bean tVilles = ville.selectTous(); for(int i=0; i<tVilles.size(); i++) { ville = (Villes)tVilles.get(i); System.out.println(ville.getNomVille()); } } } 16 avril 2017 - Page 63 Java - JDBC 2.6 INTROSPECTION ET SQL Cf le support java_intro.doc pour l'introspection. 16 avril 2017 - Page 64