Java et Objet Amélie Lambert 2014-2015 Amélie Lambert 2014-2015 1 / 58
Chapitre 11 Java Data Base Connectivity (JDBC) Amélie Lambert 2014-2015 2 / 58
Plan du cours Introduction aux base de données Introduction à JDBC Les requêtes et l interface ResultSet Exercice Amélie Lambert 2014-2015 3 / 58
Introduction aux base de données Définition Système de Gestion de Bases de Données Le modèle relationnel Schéma Entité/Association Le langage SQL Exemples Amélie Lambert 2014-2015 4 / 58
Bases de Données : Définition Ensemble d informations (centralisées ou non) sur un sujet particulier qui soit : Exhaustif (qui traite totalement le sujet). Non redondant. Structuré. persistant (conservation des données). interrogeable et modifiable par des utilisateurs travaillant en parallèle. Amélie Lambert 2014-2015 5 / 58
Système de Gestion de Bases de Données (SGBD) (1/2) C est un logiciel qui permet de : décrire, modifier, interroger, administrer, les données d une base de données dans un langage "naturel". Amélie Lambert 2014-2015 6 / 58
Système de Gestion de Bases de Données (SGBD) (2/2) Avec les propriétés suivantes : Efficacité temps de réponse, optimisation des requêtes (minimisation des accès disque). Non redondance pour éviter les problèmes de mise à jour. Cohérence des données grâces aux contraintes d intégrité définissant un état cohérent de la base. Partageabilité des données accès simultané. Résistance aux pannes revenir à un état sain. Amélie Lambert 2014-2015 7 / 58
Le modèle relationnel Indépendance entre le niveau physique et le niveau logique. Les données sont organisées sous la forme de tables (relations). Les données sont manipulées par des opérateurs de l algèbre relationnelle à travers un langage de haut niveau. L état cohérent de la base est défini par un ensemble de contraintes d intégrité. Amélie Lambert 2014-2015 8 / 58
Conception d une base (1/2) Traitement des données dans un simple fichier texte : Anomalies possibles : A l insertion 2 mêmes titres et réalisateurs différents. A la modification on modifie l année de naissance d Hitchcock dans Psychose et pas dans Vertigo. A la destruction si on supprime un film, on supprime aussi son réalisateur. Amélie Lambert 2014-2015 9 / 58
Conception d une base (2/2) Pour éviter les anomalies possibles : Séparer la représentation des films et des réalisateurs plus de redondance (Hitchcock n est représenté qu une seule fois). Identifier un film de manière unique (le titre par exemple) ou un réalisateur par un Id. Établir un lien entre film et réalisateur (sans introduire de la redondance) lien établi entre film et réalisateur par l IdReal. Amélie Lambert 2014-2015 10 / 58
Schéma Entité/Association Amélie Lambert 2014-2015 11 / 58
Du schéma E/A au schéma relationnel (1/3) On passe d un modèle à 2 structures (entités et associations) à un modèle uniquement constitué de tables. Transcription des entités en tables : Chaque colonne de la table représente un attribut de l entité. Chaque table doit avoir une clé (identification unique pour ses lignes). Amélie Lambert 2014-2015 12 / 58
Du schéma E/A au schéma relationnel (2/3) Transcription d une association de 1 à n : La clé de la table Artiste devient aussi un attribut de Film. Dans Film, IdReal = id de Artiste (une ligne de Artiste ne référence qu une et une seule ligne de Film). La clé de Artiste exportée vers Film est appelée clé étrangère. Amélie Lambert 2014-2015 13 / 58
Du schéma E/A au schéma relationnel (3/3) Transcription d une association de n à n : Création d une table pour l association. La clé de cette table est constituée de la paire (clé Artiste+clé Film). Les attributs de l association deviennent les attributs de la nouvelle table. Amélie Lambert 2014-2015 14 / 58
Le langage SQL Les données de la base sont définies dans le langage LDD (Data Definition Language), sous ensemble du langage SQL. Amélie Lambert 2014-2015 15 / 58
Création de la base Création des tables dans le langage SQL : CREATE DATABASE films; Différents types de privilèges peuvent être accordés aux utilisateurs : GRANT ALL PRIVILEGES ON Films TO admin@localhost IDENTIFIED BY admin Pour travailler avec une base particulière : USE Films; Pour détruire une base : DROP DATABASE Films; Amélie Lambert 2014-2015 16 / 58
Création des tables (1/2) CREATE TABLE Film ( titre VARCHAR (50) NOT NULL, annee INTEGER NOT NULL, genre VARCHAR (10), resume TEXT, idreal INTEGER, PRIMARY KEY (titre), FOREIGN KEY (idreal) REFERENCES Artiste ); NOT NULL donne l obligation d initialiser la variable. FOREIGN KEY référence la clé primaire d une autre table (ici la table Artiste). Amélie Lambert 2014-2015 17 / 58
Création des tables(2/2) CREATE TABLE Artiste ( id INTEGER AUTO_INCREMENT NOT NULL, nom VARCHAR (30) NOT NULL, prenom VARCHAR (30) NOT NULL, naissance INTEGER, PRIMARY KEY (id), UNIQUE(nom,prenom) ); Pour détruire une table : DROP TABLE IF EXISTS Film; Amélie Lambert 2014-2015 18 / 58
Insertion de données Syntaxe : INSERT INTO nom_table (colonne1, colonne2,...) VALUES ( valeur1, valeur2,...); Exemple : INSERT INTO Film (titre,annee) VALUES ( Magnolia, 1999); INSERT INTO Artiste (nom, prenom, naissance) VALUES ( Anderson, Paul, 1970); Amélie Lambert 2014-2015 19 / 58
Mise à jour de données Syntaxe : UPDATE nom_table1, nom_table2,... SET colonne1 = valeur1, colonne2=valeur2,... WHERE condition; Exemple : UPDATE Artiste SET prenom = Paul-Thomas WHERE nom= Anderson AND naissance =1970 ; UPDATE Film, Artiste SET Film.idReal = Artiste.id WHERE Artiste.nom= Hitchcock and Artiste.prenom= Alfred ; Amélie Lambert 2014-2015 20 / 58
Destruction de données Syntaxe : DELETE FROM nom_table WHERE condition; Exemple : DELETE FROM Film WHERE titre= Pulp-Fiction ; Amélie Lambert 2014-2015 21 / 58
Sélection de données Syntaxe : SELECT colonne1, colonne2,... FROM table1, table2,... WHERE condition; où condition est une expression sur les attributs des tables du FROM. Les opérateurs applicables sont : opérateurs arithmétiques : +,*,-,... opérateurs relationnels : <,>,>=,...,!= opérateurs logiques : AND, NOT, OR BETWEEN, IN, LIKE Les caractères joker sont : _ qui remplace n importe quel caractère % qui remplace n importe quelle chaîne de caractères Exemple : SELECT * FROM Film; SELECT titre FROM Film, Artiste WHERE Film.idReal = Artiste.id; Amélie Lambert 2014-2015 22 / 58
Exemples SELECT * FROM Boutique WHERE nom IN ( Dijon, Lyon ) SELECT * FROM Boutique WHERE Date BETWEEN 06-Jan-2009 AND 11-Jan-2009 SELECT * FROM Boutique WHERE nom LIKE %ON% SELECT nom FROM Boutique WHERE ventes > 1000 OR (ventes < 500 AND ventes > 275) Amélie Lambert 2014-2015 23 / 58
Exercice Dans un système de covoiturage, on distingue les usagers conducteurs de voiture qui proposent des offres de covoiturage et les usagers piéton qui s inscrivent à une offre. Les conducteurs sont caractérisés par leur nom, leur prénom et leur n de téléphone. Les offres mémorisent la destination du voyage, l heure et le lieu du RDV et le nombre de places offertes. Pour qu un piéton reconnaisse la voiture pour laquelle il s est inscrit, celle-ci lui est décrite par ses modèle, couleur et immatriculation. 1 Construire le modèle relationnel de la BD 2 Créer la base et ses tables dans le langage sql 3 Insérer quelques données dans les tables : Bauer, Jack, 0967983412 et Twingo, verte, BE 194 XZ 4 Sélectionner toutes les offres pour la destination Lille 5 Sélectionner toutes les offres pour lesquelles le pieton Bauer est inscrit 6 Sélectionner le nom du conducteur d un véhicule pour la destination Brest Amélie Lambert 2014-2015 24 / 58
Correspondances des types de données SQL/Java Amélie Lambert 2014-2015 25 / 58
Introduction à JDBC Amélie Lambert 2014-2015 26 / 58
Introduction à JDBC Pour les applications web utilisant une ou plusieurs bases de données, les servlets et l API JDBC offrent une solution : efficace, la connexion est maintenue durant tout le cycle de vie de la servlet et non à chaque invocation. flexible, l accès à une base de données dépend peu de son fournisseur. Il est facile de porter une application web vers une base de données d un autre fournisseur. Amélie Lambert 2014-2015 27 / 58
Principe de fonctionnement de JDBC Permet à un programme Java d interagir : localement ou à distance. avec une base de données relationnelle. Fonctionne selon un principe client/serveur : client = le programme Java. serveur = la base de données. Principe : le programme Java ouvre une connexion, il envoie des requêtes SQL, il récupère les résultats,... il ferme la connexion. Amélie Lambert 2014-2015 28 / 58
Architecture 3 tiers Les trois couches sont rendues indépendantes grâce à l utilisation d interfaces Java Amélie Lambert 2014-2015 29 / 58
API JDBC l API JDBC se trouve dans le paquetage java.sql. l API JDBC est constituée d un ensemble d interfaces pour interagir avec des bases de données. l API JDBC ne fournit donc aucune implémentation des comportements spécifiés par les interfaces. l API JDBC permet d exécuter des instructions SQL et de récupérer les résultats. La version la plus récente de l API est la version 3.0. Amélie Lambert 2014-2015 30 / 58
Pilotes JDBC (1/2) Le pilote JDBC a pour rôle de permettre l accès à un système de bases de données particulier. Il gère le détail des communications avec un type de SGBD. A une API JDBC correspond plusieurs implémentations selon les fournisseurs (un type de driver par SGBD Oracle, Sybase, Access,...). Il en existe pour la plupart des SGBD relationnels Le pilote implémente l interface java.sql.driver. Il existe un driver générique JDBC-ODBC pour toutes les données accessibles par ODBC. SGBD : MS Access, SQL Server, Oracle, dbase,... tableurs : Excel,... tout autre application conforme ODBC. Amélie Lambert 2014-2015 31 / 58
Gestionnaire de pilotes DriverManager DriverManager est une classe, gestionnaire de tous les drivers chargés par un programme Java. Chaque programme Java charge le (ou les) drivers dont il a besoin. L enregistrement des pilotes est automatique. Amélie Lambert 2014-2015 32 / 58
Java et les BD Amélie Lambert 2014-2015 33 / 58
Connexion à une base de données Disposer de l URL d un pilote pour le SGBD : com:mysql:jdbc:driver Sun:jdbc:odbc:JdbcOdbcDriver Charger le pilote (création d une instance du pilote et enregistrement automatique auprès du DriverManager) : Class.forName("com:mysql:jdbc:Driver"); Etablir l URL (protocole) de la base : String dburl="jdbc:mysql://localhost:3306/mabd"; Ouvrir la connexion : le DriverManager choisit le pilote approprié à cette URL parmi l ensemble des pilotes disponibles. Connection dbcon = DriverManager.getConnection(dbUrl,user,password); Amélie Lambert 2014-2015 34 / 58
Code de connexion : un exemple try { //Déclaration du driver : Class.forName("com.mysql.jdbc.Driver"); //Url de connexion String dburl="jdbc:mysql://localhost:3306/labobd"; //Profil/mot de passe String user = "root"; String password = "19AB5"; //connexion à la base dbcon = DriverManager.getConnection(dbUrl,user,password); } catch( ClassNotFoundException e ){ // erreur de chargement du pilote } catch( SQLException e ){ // erreur d obtention de la connexion } finally{ // fermeture de la connexion pour libérer les ressources de la BD try{ if (dbcon!=null) dbcon.close(); } catch(sqlexception e){...} } Amélie Lambert 2014-2015 35 / 58
Les requêtes et l interface ResultSet L interface ResultSet Les requêtes interprétées Les requêtes préparées Les requêtes stockées Amélie Lambert 2014-2015 36 / 58
Il existe 3 types de requêtes Amélie Lambert 2014-2015 37 / 58
L interface ResultSet Un objet de type ResultSet est une table représentant le résultat d une requête à une base de données. Le nombre de lignes du tableau peut être nul. Les données de la table sont accessibles ligne par ligne grâce à un curseur. Un resultset gère un curseur sur la ligne courante de la table des données satisfaisant aux conditions de la requête. Amélie Lambert 2014-2015 38 / 58
Exécution d une requête SQL de type Statement (interprétée) (1/3) Le type de résultat obtenu dépend de la manière dont on souhaite manipuler le ResultSet. Il existe : 3 constantes de types : TYPE_FORWARD_ONLY : le curseur se déplace uniquement vers l avant. TYPE_SCROLL_INSENSITIVE : le curseur se déplace en avant et en arrière mais le Resultset est insensible aux modifications apportées à la BD durant le traitement. TYPE_SCROLL_SENSITIVE : le curseur se déplace en avant et en arrière mais les changements faits à la BD durant le traitement sont reflétés dans le ResultSet. 2 constantes de concurrence : CONCUR_READ_ONLY : les données du ResultSet ne peuvent pas être modifiées. CONCUR_UPDATABLE : des modifications de la BD peuvent être effectuées via le ResultSet. Amélie Lambert 2014-2015 39 / 58
Exécution d une requête SQL de type Statement (interprétée) : exemple (2/3) Créer un objet de la classe java.sql.statement : Statement stmt = dbcon.createstatement(resultset.type_scroll_insensitive, ResultSet.CONCUR_READ_ONLY); // indique que le ResultSet est scrollable et non modifiable. // ResultSet.CONCUR_UPDATABLE indiquerait qu un seul utilisateur à la fois // peut modifier la donnée Statement stmt = dbcon.createstatement(resultset.type_scroll_sensitive, ResultSet.CONCUR_UPDATABLE); // lorsqu on apporte un changement au ResultSet, on peut y accéder par la // suite car le type est "scrollable" et on peut récupérer sa valeur car //le type est "SENSITIVE" Pour que les modifications apportées au Resultset prennent effet dans la base, il faut appliquer les méthodes updaterow. Amélie Lambert 2014-2015 40 / 58
Exécution d une requête SQL de type Statement (interprétée) (3/3) Par défaut, le ResultSet n est ni scrollable, ni modifiable : Statement stmt = dbcon.createstatement(); dbcon.createstatement(type_forward_only, CONCUR_READ_ONLY); Construire la requête SQL : Soit la table personne(nom,prenom,age) String reqsql = "select * from personne"; Exécuter la requête : ResultSet rs = stmt.executequery( reqsql ); Amélie Lambert 2014-2015 41 / 58
Exploiter les résultats d une requête (1/5) A la création du ResultSet, le curseur est placé avant la première ligne (numéro 1). Pour le déplacer, on dispose des méthodes : next() déplacement d une ligne en avant. previous() déplacement d une ligne en arrière. first() déplacement vers la première ligne. last() déplacement vers la dernière ligne. beforefirst() déplacement avant la première ligne. Si le ResultSet est vide, cela n a aucun effet. afterlast() déplacement après la dernière ligne. Si le ResultSet est vide, cela n a aucun effet. relative(int i) déplace de i lignes par rapport à la position courante. absolute(int i) déplace le curseur vers la i-ème ligne. Amélie Lambert 2014-2015 42 / 58
Exploiter les résultats d une requête (2/5) Déplacement absolu absolute( int i) : i>0 déplacement vers la ligne numéro i rs.absolute(1) = déplacement vers la ligne 1 i<0 déplacement à partir de la fin rs.absolute(-1) = déplacement sur la dernière ligne rs.absolute(-3) = si 30 lignes, déplacement vers ligne 28 Déplacement relatif relative( int i) : On spécifie le nombre de déplacements à partir de la ligne courante. i>0 = déplacements en avant i<0 = déplacements en arrière rs.absolute(4); // curseur sur la 4ème ligne rs.relative( 3); // curseur sur la première ligne rs.relative(2); // curseur sur la 3ème ligne Amélie Lambert 2014-2015 43 / 58
Exploiter les résultats d une requête (3/5) On récupère le contenu d une ligne du ResultSet colonne par colonne. Les méthodes d accès sont construites sur le modèle : getxxx (XXX étant un type primitif ou String). La colonne est spécifiée soit par son nom, soit par son numéro (la première colonne est numérotée 1) : par son nom : String getstring(string nomattribut) float getfloat(string nomattribut) par le numéro de la colonne qui lui correspond : String getstring(int indexcolonne) float getfloat(int indexcolonne) idem pour les int, double, long, boolean, Object Amélie Lambert 2014-2015 44 / 58
Exploiter les résultats d une requête (4/5) Pour obtenir le numéro de la ligne courante : int getrow() Exemple : rs.absolute(5); int i = rs.getrow(); // i=5 Pour tester la position dans le Resultset : isfirst, islast, isbeforefirst, isafterlast. Exemple : if (rs.isafterlast() == false) { rs.afterlast(); } Amélie Lambert 2014-2015 45 / 58
Exploiter les résultats d une requête (5/5) String reqsql = "select from personne"; ResultSet rs = stmt.executequery( reqsql ); while (rs.next()){ String prenom = rs.getstring("prenom"); int age = rs.getint("age"); } Amélie Lambert 2014-2015 46 / 58
Mises à jour de table (1/2) Il est préférable que le ResultSet soit scrollable lors d une mise à jour : Statement stmt = con.createstatement(resultset.type_scroll_sensitive, ResultSet.CONCUR_UPDATABLE); Pour mettre à jour, 2 méthodes : updatexxx avec 2 paramètres (nom et valeur de la colonne) updaterow() rendre effective la mise à jour Amélie Lambert 2014-2015 47 / 58
Mises à jour de table (2/2) Nom Prénom Age Meyer René 54->37 Legrand Léa 18 Dupont Marcel->Robert 43 String reqsql = "select from personne"; ResultSet rs = stmt.executequery( reqsql ); rs.next(); rs.updateint("age",37); rs.last(); rs.updatestring("prénom","robert"); rs.updaterow(); Amélie Lambert 2014-2015 48 / 58
L interface ResultSetMetaData (1/2) Permet d obtenir la description du contenu du ResultSet : ResultSetMetaData metadata = rs.getmetadata(); A partir de cette information, obtenir le nombre de colonnes du résultat : int nbcols = metadata.getcolumncount(); Obtenir le nom de la colonne connaissant son indice (à partir de 1) : String nomcol = metadata.getcolumnname( int i ); Amélie Lambert 2014-2015 49 / 58
L interface ResultSetMetaData : Exemple (2/2) ResultSet rs = stmt.executequery( "SELECT FROM personne" ); StringBuffer resultat = new StringBuffer(); ResultSetMetaData metadata = rs.getmetadata(); int nbcols = metadata.getcolumncount(); for ( int i=1;i<=nbcols;i++ ) resultats.append( metadata.getcolumnname( i )+"\t" ); resultats.append( "\n" ); while ( rs.next() ){ for ( int i=1;i<=nbcols;i++ ) // pour simplifier, chaque donnée est du type Object // sinon le type de la valeur est obtenu par getcolumntype resultats.append( rs.getobject( i )+"\t" ); resultats.append( "\n" ); } Amélie Lambert 2014-2015 50 / 58
Exécution d une requête SQL de type PreparedStatement (préparée) (1/4) L exécution de chaque requête à une BD nécessite 4 étapes : L analyse La compilation L optimisation L exécution Pour des requêtes identiques, les 3 premières étapes n ont pas à être effectuées de nouveau. Avec la notion de requête préparée, les 3 premières étapes ne sont effectuées qu une seule fois. JDBC propose l interface PreparedStatement qui dérive de l interface Statement pour modéliser cette notion. Amélie Lambert 2014-2015 51 / 58
Exécution d une requête SQL de type PreparedStatement (préparée) (2/4) Avec l interface Statement, on écrivait : Statement smt = dbcon.createstatement(); ResultSet rs = smt.executequery("select * FROM personne" ); Avec l interface PreparedStatement, on écrit : PreparedStatement psmt = dbcon.preparestatement("select * FROM personne" ); ResultSet rs = psmt.executequery(); On voit que la requête est préparée à l avance et n est donc pas transmise en argument au moment de l exécution ( executequery()). Amélie Lambert 2014-2015 52 / 58
Exécution d une requête SQL de type PreparedStatement (préparée) (3/4) Pour préparer des requêtes paramétrées de la forme : SELECT nom FROM Personnes WHERE age >? AND adresse =? On utilise les PreparedStatement avec les méthodes settype(numérodelargument, valeur) : Type représente le type de l argument numérodelargument représente le numéros de l argument (commençant à 1 dans l ordre d apparition dans la requête). valeur représente la valeur qui lui est associée Exemple : PreparedStatement psmt = dbcon.preparestatement ("SELECT nom FROM Personne WHERE age >? AND prenom=?" ); psmt.setint(1, 22); psmt.setstring(2, "Adrien"); ResultSet rs = psmt.executequery(); Amélie Lambert 2014-2015 53 / 58
Exécution d une requête SQL de type PreparedStatement (préparée) (4/4) PreparedStatement psmt = dbcon.preparestatement( "update personne set nom =? where prenom like?"); psmt.setstring(1, "Bauer"); psmt.setstring(2, "René"); int i = psmt.executeupdate(): On a changé en Bauer le nom de la personne dont le prénom est René. La valeur retournée par executeupdate() est le nombre de lignes mises à jour. Amélie Lambert 2014-2015 54 / 58
Exécution d une requête SQL de type CallableStatement (stockée) (1/2) Les procédures stockées permettent d embarquer du code procédural directement dans la base. Elles exécutent une ou plusieurs requêtes SQL. Intérêt : Elles sont précompilées. Ne nécessitent pas de trafic réseau. JDBC utilise la classe java.sql.callablestatement. Syntaxe d appel des procédures stockées : {call nom-proc-stokée(?,?)} // procédure sans résultat {?=call nom-proc-stokée(?,?)} // retour d une valeur Amélie Lambert 2014-2015 55 / 58
Exécution d une requête SQL de type CallableStatement (stockée) (2/2) CallableStatement cstmt = dbcon.preparecall("{call nom proc stokée(?,?)}"); cstmt.registeroutparameter(2,java.sql.types.float); // indique que le second paramètre donne le résultat cstmt.setint(1,id); // fixe la donnée en entrée cstmt.execute(); //exécute la procédure stockée System.out.println("Solde : " +cstmt.getfloat(2); // affiche le résultat de l exécution de la procédure // stockée figurant dans le second paramètre Amélie Lambert 2014-2015 56 / 58
Exercices Amélie Lambert 2014-2015 57 / 58
Exercice 1 (1/4) Soit une BD de nom "mags", constituée de la seule table magasins : (ID, magasin, produit, prix) Cette BD est accessible avec les identifiants ("root", "2dwsk8") Ecrire le morceau de code Java permettant d afficher le résultat de la requête : "liste des produits dont le prix est inférieur à 50 euros" sous la forme : produit prix............ On utilisera pour cela les requêtes préparées de JDBC Compléter le code pour modifier la table afin de ramener les prix de 50 euros à 49,95 euros Amélie Lambert 2014-2015 58 / 58