Module JEE API JDBC La route vers la
Module JEE API JDBC La route vers la base de données
JDBC • Java Database Connectivity • API § § définissant la manière dont un client peut se connecter à une base de données Un ensemble de classes et méthodes pour requêter, créer et mettre à jour des données • Package « java. sql »
JDBC Driver • Composant logiciel permettant de se connecter à une base de données • 4 types de drivers : § § Type 1 : ODBC-JDBC bridge Type 2 : Native API Driver Type 3 : Driver écrit en Java utilisant un middleware Type 4 : Driver écrit en Java utilisant le protocole réseau pour communiquer avec la BD. [Le plus utilisé]
JDBC Drivers 1 / 2 / 3 Type 1 Type 2 Type 3 Application API JDBC ODBC Driver Native API Driver Type 3 Native API Middle. Ware ODBC SGBD
JDBC Driver Type 4 Application API JDBC Drivers Postgre. SQL Drivers My. SQL / Mariad. DB Drivers Oracle Drivers DB 2 Posgre SQL Mysql Maria. DB Oracle DB 2
Accès à une BD : 5 étapes Chargement du driver Etablissement de la connexion Création de la requête Exécution et extraction des résultats Fermeture des ressources et de la connexion
Chargement du driver Etablissement de la connexion Chargement du driver Création de la requête Exécution et extraction des résultats Fermeture des ressources et de la connexion • Utilisation de la méthode « Class. for. Name » pour charger le pilote § § My. SQL try { Class. for. Name("com. mysql. jdbc. Driver"); } catch (Class. Not. Found. Exception e) { throw new Runtime. Exception(e); } Postgre. SQL try { Class. for. Name("org. postgresql. Driver"); } catch (Class. Not. Found. Exception e) { throw new Runtime. Exception(e); } Cette étape n’est plus obligatoire. La version JDBC 4 détecte les drivers automatiquement
Etablissement de la connexion Chargement du driver Etablissement de la connexion Création de la requête Exécution et extraction des résultats • Via l’utilisation de la méthode « Driver. Manager. get. Connection » public Connection get. Connection() throws SQLException{ return Driver. Manager. get. Connection( "jdbc: mysql: //localhost: 3306/db_contact", "login", "p@ssword. Securise"); } Fermeture des ressources et de la connexion
Création des requêtes Chargement du driver Etablissement de la connexion Création de la requête Exécution et extraction des résultats • A partir de l’instance de Connection, création d’un requête SQL conn = Connection. Factory. get. Instance(). get. Connection(); Statement st = conn. create. Statement(); Fermeture des ressources et de la connexion
Exécution des requêtes et extraction des données Chargement du driver Etablissement de la connexion Création de la requête Exécution et extraction des résultats • Exécution de la requête SELECT via « execute. Query » • Exécution de la requête INSERT/UPDATE/DELETE via « • Extraction des résultats via le parcours du « Result. Set » Fermeture des ressources et de la connexion execute. Update » rs = st. execute. Query("select identifier, last_name, first_name, phone_number from contact"); while(rs. next()) { Contact contact = new Contact(); contact. set. Identifier(rs. get. Long("identifier")); contact. set. Last. Name(rs. get. String("last_name")); contact. set. First. Name(rs. get. String("first_name")); contact. set. Phone. Number(rs. get. String("phone_number")); ret. add(contact) }
Fermeture de la connexion Chargement du driver Etablissement de la connexion Création de la requête Exécution et extraction des résultats Fermeture des ressources et de la connexion • Obligatoire afin de libérer la connexion entre l’application Java et la BD • Utilisation de la méthode « conn. close() » }finally { /* liberation rs, st */ try { if(conn != null) { conn. close(); } } catch (SQLException ignore) { } } • Fermeture dans le finally • Utilisation du try-catch-resources • Les autres ressources « Statement » et « Result. Set » doivent être libérées
Interface « Connection » • Session entre l’application Java et la base de données • « Factory » permettant de créer des instances de § § § Statement Prepared. Statement Callable. Statement conn. create. Statement() conn. prepare. Statement( « query » ) conn. prepare. Call( « query » ) • Fournit des méthodes pour gérer les transactions § § § Activation de la transaction Validation de la transaction Annulation de la transaction conn. set. Auto. Commit(false) conn. commit() conn. rollback() • Une connexion doit être libérée en fin d’utilisation
Interface Statement • Permet de réaliser des requêtes avec la base de données • « Factory » de Result. Set • Fournit les méthodes : § § § : exécution d’une requête SQL avec Result. Set execute. Update ( « sql » ): exécution d’une requête de mise à jour retournant le nombre de lignes mise à jour ou crées execute ( « sql » ). : exécution de multiple instructions SQL execute. Query ( « sql » ) • Ressource devant être libérée Doit être utilisée pour des requêtes simples non issues d’une concaténation ou d’élements variants (RISQUE SQL INJECTION)
Interface Prepared. Statement • Étend la classe « Statement » A Pr ivilé gier • Permet de réaliser des requêtes précompilées § § Améliorant les performances Permettant d’exécuter plusieurs fois la même requêtes en faisant varier les paramètres • Protège contre de l’injection SQL
Interface Prepared. Statement • Fournit un ensemble de méthodes pour renseigner les valeurs de chaque paramètre. § set<Type>(index, valeur) • Exemple : § § § set. Int permet de renseigner la valeur d’un entier set. String pour une chaine de caractères set. Date pour une date Note : Index commence à 1
Interface Prepared. Statement public List<Contact> save. All(List<Contact> contacts) { try ( Connection conn = Connection. Factory. get. Instance(). get. Connection(); Prepared. Statement ps = conn. prepare. Statement( "insert into contact(first_name, last_name, phone_number)values(? , ? )") ){ for (Contact contact : contacts) { ps. set. String(1, contact. get. First. Name()); ps. set. String(2, contact. get. Last. Name()); Déclaration du prepared. Statement Réutilisation Renseignement des paramètres ps. set. String(3, contact. get. Phone. Number()); ps. execute. Update(); Result. Set rs = ps. get. Generated. Keys(); if (rs. next()) { contact. set. Identifier(rs. get. Long(1)); } rs. close(); } } catch (SQLException e) { LOGGER. error("Problem SQL", e); } return contacts; } Récupération de la clé auto générée (ATTENTION : spécifique à certains SGBD )
Interface Callable. Statement • Étend la classe « Prepared. Statement » • Permet d’exécuter des procédures stockées • Syntaxe de la requête SQL § § Pour les procédures stockées : « {call nom. Procédure[(? , ? …)]}» Pour les fonctions : «{ ? = call nom. Procédure[(? , ? …)]}» • Remplacement et récupération des paramètres comme le Prepared. Statement
Interface Result. Set • Curseur sur les résultats de la requête • Propose des méthodes pour manipuler le curseur : § rs. next() § rs. previous() § rs. fisrt() § rs. last() § rs. absolute(n) § rs. get. Meta. Data() retournés positionne le curseur sur le résultat suivant positionne le curseur sur le résultat précédent positionne le curseur sur le premier résultat positionne le curseur sur le dernier résultat permet de déplacer le curseur de n résultats permet de récupérer les informations sur les colonnes
Interface Result. Set • Propose des méthodes pour extraire les données du curseur § De la forme « rs. get<Type> » avec en paramètre • soit le nom de la colonne • soit l’index de la colonne. § Exemples de méthodes : • • rs. get. String (…) rs. get. Int(…) rs. get. Double(…) rs. get. Date(…) permet d’extraire un chaine de caractères permet d’extraire un Integer permet d’extraire un Double permet d’extraire une Date
Interface Result. Set List<Contact> ret = new Array. List<>(); Result. Set rs = st. execute. Query("select identifier, last_name, first_name, phone_number from contact"); Déplacement du curseur sur le résultat suivant while (rs. next()) { Contact contact = new Contact(); contact. set. Identifier(rs. get. Long("identifier")); contact. set. Last. Name(rs. get. String("last_name")); contact. set. First. Name(rs. get. String("first_name")); contact. set. Phone. Number(rs. get. String("phone_number")); ret. add(contact); } Extraction des valeurs pour chaque colonne en spécifiant le type.
Interface Result. Set. Meta. Data • Permet d’obtenir des informations sur les colonnes du resultset • Exemple de méthodes : § get. Column. Count nombre de colonnes retournées § get. Column. Name retourne le nom de la colonne § get. Column. Type retourne le type de la colonne
Interface Result. Set. Meta. Data rs. Meta. Data = rs. get. Meta. Data(); for (int index = 1; index <= rs. Meta. Data. get. Column. Count(); index++) { LOGGER. debug(" Nom de la colonne : {}", rs. Meta. Data. get. Column. Name(index)); LOGGER. debug(" Type de la colonne : {}", rs. Meta. Data. get. Column. Type. Name(index)); LOGGER. debug(" Precision de la colonne : {}", rs. Meta. Data. get. Precision(index)); }
Les transactions • Permet de valider l’intégralités des traitements (insertion, mise à jour, suppression) • Portées par l’objet « connection » • Par défaut, le mode est en autocommit § Chaque traitement est validé dés l’exécution de la requête • Pour désactiver le mode : conn. set. Auto. Commit(false);
Les transactions try { conn = Connection. Factory. get. Instance(). get. Connection(); ps = conn. prepare. Statement("insert into contact(first_name, last_name, phone_number)values(? , ? )"); conn. set. Auto. Commit(false); for (Contact contact : contacts) { //Insertion } conn. commit(); } catch (SQLException e) { try { conn. rollback(); }catch (SQLException e 1) { } LOGGER. error("Problem SQL", e); } finally { close(ps); close(conn); } Désactivation de l’autocommit Réalisation de l’ensemble des insertions Tout est Ok. Commit Exception levée. Rollback. Aucun enregistrement n’est inséré
Les Data. Sources • Depuis JDBC 3, ajout de la classe « Data. Source » pour réaliser des connexions aux bases de données • 2 manières d’obtenir une datasource § § Soit en l’instanciant manuellement Soit en demande sa résolution par JNDI.
Les Datasources Mysql. Data. Source ds = new Mysql. Data. Source(); ds. set. URL(this. url); ds. set. Password(this. password); ds. set. User(this. user. Name); Connection conn = ds. get. Connection();
JNDI • Java Naming And Directory Interface est un service de nommages ou d’annuaires permettant d’accéder à des services et essentiellement utilisé sur les serveurs JEE • Cas d’usage les plus fréquents § § Accéder à une datasource JDBC Accéder à des EJB Accéder à des URL ou des variables Accéder et parcourir un annuaire LDAP
Data. Source avec JNDI <Context doc. Base="epsi-persistence" path="/epsi-persistence" reloadable="true" source="org. eclipse. jst. j 2 ee. server: epsi-persistence"> <Resource name="jdbc/contact" auth="Container" type="javax. sql. Data. Source" max. Total="100" max. Idle="30" max. Wait. Millis="10000" username="root" password="password" driver. Class. Name="com. mysql. jdbc. Driver" url="jdbc: mysql: //192. 168. 99. 100: 3306/contact"/> </Context> private void inialize. With. Jndi() { Initial. Context context = null; try { context = new Initial. Context(); this. ds = (Data. Source)context. lookup("java: /comp/env/jdbc/contact"); } catch (Naming. Exception e) { throw new Runtime. Exception(e); }finally { close(context); } } Pour un serveur Tomcat, configurer la ressource JDBC Résolution du contexte Le jar mysql doit être ajoutée dans le répertoire lib du serveur Tomcat
JNDI L’application n’a pas à connaitre les paramètres de configuration (URL, login, mot de passe) pour se connecter à une base de données. Le war de l’application n’embarque pas le driver du SGBD.
JDBC et Performance • Utiliser des pool de connexion et réutiliser des connexions • Utiliser le mode « batch » pour des insertions en masse • Modifier le fetch. Size (resulset) pour augmenter le nombre de resultats remontés lors de chaque échange avec la base de données • Privilégier les prepared. Statement pour augmenter la réutilisabilité des plans d’exécution • Limiter le nombre de données remontées pour un résultat (dixit ne pas utiliser étoile * mais indiquer les colonnes souhaité)
Où implémenter les accés ? • Pattern DAO : DTO § Data Access Object Servlet / JSP / Spring MVC / JSF / RS-* BO VO • Permet d’accéder aux données (BD, WS…) Services DAO API JDBC DB ICI ! • Classe fournissant des méthodes de manipulation des données • Récupération find. All / find. By • Création save • Mise à jour update • Suppression delete
- Slides: 31