JAVA, JDBC et liaison base de données
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

JAVA, JDBC et liaison base de données

  • 2,563 views
Uploaded on

Quelques notions de base pour se connecter à une base de données en Java

Quelques notions de base pour se connecter à une base de données en Java

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
2,563
On Slideshare
2,562
From Embeds
1
Number of Embeds
1

Actions

Shares
Downloads
55
Comments
1
Likes
1

Embeds 1

http://www.linkedin.com 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Java et bases de données JDBC - Hibernate Version du 05/12/2013
  • 2. JDBC • • • API orientée objet unifiée d’accès aux SGBD Soumission de requête via un driver Accès aux SGBD • • Soit par un driver JDBC adapté Soit par des passerelles • (ex : passerelle JDBC->ODBC)
  • 3. Process de requétage 1. Chargement du driver 2. Connexion à la base 3. Création de Statement • • Envoi de la requête Avec ou sans préparation 4. Prise en compte du résultat éventuel • Via un ResultSet 5. Fermeture de la connexion
  • 4. 1 - Chargement du driver On utilise les prototypes de java.sql import java.sql.*; ! class Cnx Accès direct au driver { par une chaîne de public Cnx() { caractères try 
 { Class.forName("com.mysql.jdbc.Driver").newInstance(); } catch (ClassNotFoundException e) { System.out.println("Driver spécifié non trouvé");
 throw e; } }
 }
  • 5. 2 - Connexion à la base try { dbC=DriverManager.getConnection ("jdbc:mysql://localhost/Bibliotheque","user","passwd"); } catch (SQLException e) { System.out.println("Impossible de se connecter sur la base") ; System.out.println(e) ; }
  • 6. Comment récupérer la connexion ? • Il faut éviter à tout prix de relancer X fois la procédure “chargement driver / connexion” • Outil de préservation d’unicité : le singleton Connection cnx=Cnx.getCnx().getConnection(); • Dans un contexte Web, on peut passer par les séquences d’initialisations du serveur • Utilisation de Pools de connexion
  • 7. ! 3 - Création de Statement try
 { // dbC est l'instance de connexion Statement st=cnx.createStatement(); 
 // Exemple de requête avec résultat
 ResultSet rs=st.executeQuery("SELECT * FROM table");
 
 // Exemple de requête sans résultat
 st.executeUpdate
 ("DELETE FROM table WHERE num = 1");
 rs.close(); } catch(SQLException e) {
 }
  • 8. 4 - Exploitation des résultats • • Après le SELECT : Exploitation du ResultSet Accès aux colonnes par : • Index (à partir de 1) XXX getXXX(int index); • Nom de colonne XXX getXXX(String nomCol);
  • 9. Exemple de parcours d’un ResultSet while(rs.next())
 {
 int num=rs.getInt(“num”);
 String titre=rs.getString(“titre”);
 }
  • 10. Parcours d’un ResultSet • • • On utilise la méthode next(); Certains drivers intègrent d’autres méthodes : • • previous() relative(int mv) Toutes retournent un booléan pour inclusion directe dans un while(...)
  • 11. • 5 - Fin de connexion Il faut penser à fermer tous les objets rs.close();
 st.close();
 cnx.close(); • Il est important de fermer la connexion • • • Nombre d’accès limités par SGBD Ne pas monopoliser ces ressources ! Cas particulier : si la connexion est dans un singleton
  • 12. Récupération d’une clé générée • • Certaines tables génèrent automatiquement leur clé lors d’un INSERT • (auto_increment sous MySQL) Récupération de la clé après le INSERT • Avec JDBC>=3 : statement.getGeneratedKeys() • • Sous MySQL : SELECT LAST_INSERT_ID Autre SGBD : voir driver propriétaire
  • 13. Récupération de la clé String req=”INSERT …“; st.executeUpdate(sql); ! // Récupération avec Statement.getGeneratedKeys() rs = stmt.getGeneratedKeys(); if (rs.next()) cle = rs.getInt(1); ! // Récupération avec MySQL LAST_INSERT_ID() rs = stmt.executeQuery("SELECT LAST_INSERT_ID()"); if (rs.next()) cle = rs.getInt(1);
  • 14. Les statement préparés • Permet de faciliter l’écriture de requêtes complexes • Stockées dans le SGBD, seuls les paramètres sont envoyés d’un appel à l’autre • Permet d’éviter divers problèmes de syntaxe... • • ...et divers problèmes de sécurité + quelques bénéfices de performance
  • 15. Exemple de PreparedStatement // Création du Statement PreparedStatement phrase= dbC.prepareStatement(  " INSERT into TABLE (chaine, entier, reel) VALUES (?,?,?) "); 
 Liste de // Mise en place des paramètres paramètres phrase.setString(1, "uneChaine"); phrase.setInt(2, 56); phrase.setDouble(3, 3.314456); 
 // Exécution de la requête phrase.executeUpdate();
  • 16. Intérêts du PreparedStatement • Légèrement plus efficace (pré-exécution sur le SGBD) • Evite des problèmes de syntaxe • • Oublis de ‘ ‘ pour des chaînes, ‘ intempestifs Protège (partiellement) des injections SQL • Insertion illicites de requêtes
  • 17. Traitements batchs Connection connection = ... ; ! Statement statement = connection.createStatement();! if(connection.getMetaData().supportsBatchUpdates()){! connection.setAutoCommit(false);! statement.clearBatch(); //on supprime les anciens batch! statement.addBatch("INSERT ....");! statement.addBatch("UPDATE ...");! statement.addBatch("...");! int[] resultat = statement.executeBatch();! //voir les différents types de retour possibles! connection.commit();! connection.setAutoCommit(false);! }
  • 18. Intégration des accès à la base dans les objets • Un des rôles des objets métiers est de faire la liaison avec la base de données • 3 cas principaux sont à traiter : • • • Liaison simple une instance = un enreg Instances encapsulant des listes Structures hiérarchiques (héritage)
  • 19. Exemple d’intégration d’appels à la base • • Une classe User utilisée dans un site Web On peut : • • Se connecter avec un login/mot de passe • A vérifier avec un SELECT S’enregistrer en donnant un login, un mot de passe, un nom, une adresse... • A concrétiser avec un INSERT INTO...
  • 20. Structure de la classe User • • User C’est un objet CRUD (Create/ Read/Update/Delete) login password Exemple de création/ enregistrement :
 nom User u=new User();
 u.setNom(“.....”);
 select(login) ...
 insert() u.insert(); update() delete()
  • 21. Procédure de login • • Comment faire à la fois : • • • Contrôler si un login/pass est correct Charger les données du user (nom...) Empêcher qu’une instance de User soit incohérente en mémoire (login/pass incorrect mais encapsulés dans un objet) Solution : on utilise un constructeur • Avec une lancée d’exception éventuelle
  • 22. Constructeurs de User public class User()
 {
 public User(String login, String pwd) 
 throws UserInexistantException()
 {
 String sql=”SELECT nom FROM user
 WHERE login=’”+login+”’ AND pwd=’”+pwd+”’”;
 if(rs.next()) // le login existe
 this.nom=rs.getString(“nom”); // on charge les données
 else // le login n’existe pas
 throw new LoginIncorrectException(login);
 }
  • 23. Exploitation de liaisons 1-N • En objet : c’est un attribut qui contient des instances d’autres objets • En SGBD : c’est le résultat d’une requête avec une clé secondaire • Il va donc falloir faire une requête qui va remplir la liste • Problème : comment instancier chacun des éléments de la liste ?
  • 24. Exemple de liste en objet public class Catalogue { private ArrayList<Produit> liste; ! } public void rech(String texte) { // remplissage de la liste } public class Produit { private int cle; private String nom; ... public void load(int cle) { // lecture d’un enregistrement } }
  • 25. Remplissage “procédural” public void rech(String texte) { sql=”SELECT * FROM produit WHERE ...”; while(...) { Produit p=new Produit(); Problème : p.nom=rs.getString(“nom”); on gère la lecture d’un produit ...
 en dehors de la classe Produit liste.add(p); } }
  • 26. Remplissage “objet” public void rech(String texte) { sql=”SELECT cle FROM produit WHERE ...”; while(...) { Problème : cle=rs.getInt(“cle”); On génère un grand nombre Produit p=new Produit(); de requête (N+1 requêtes, p.load(cle); N étant le nombre de produits) liste.add(p); } }
  • 27. Solution mixte public void rech(String texte) { sql=”SELECT * FROM produit WHERE ...”; while(...) { Dans cette solution, on passe cle=rs.getInt(“cle”); à Produit directement l’objet Produit p=new Produit(); “rs” afin de traiter la requête p.load(rs); à la source liste.add(p); } }
  • 28. L’héritage dans un modèle relationnel • Problématique : il n’est pas possible de définir directement une structure d’héritage dans un système de tables • Plusieurs solutions sont possibles : • • 1 table regroupant tout • 1 table par classe fille 1 table par classe fille + 1 table pour la classe mère
  • 29. Modèle à une table • A partir d’une hiérarchie de classe Produit -> Cd ou Livre : Le type est encodé dans un champ Table produit : Cette solution est -refprod valable si CD et Livre ont peu -type
 de données divergentes -nom -prix -dureecd -nbpageslivres La table contient à la fois les infos du CD, et celles du livre
  • 30. • Une table par classe fille sans factorisation A partir d’une hiérarchie de classe Produit -> Cd ou Livre : Cette solution facilite les requêtes mais complique les recherches inter-catégories Table CD : Table Livre : -refprod -refprod -type -type -nom -nom -prix -prix La table Livre contient -dureecd -nbpages toutes les données
  • 31. • 1 table par classe fille + 1 table pour classe mère A partir d’une hiérarchie de classe Produit -> Cd ou Livre : Table produit : -refprod Cette solution concilie factorisation -type
 et particularité des types de produits -nom -prix Table CD : Table Livre : -refprod -refprod -dureecd -nbpages La table Livre contient uniquement les données propres au livre
  • 32. Lecture base d’une classe polymorphe • On passe par une Factory qui va délivrer suivant les cas une instance de CD, de Livre... Produit p=ProduitFactory.getProduit(int cle);
  • 33. Factory modèle à 1 table public static Produit getProduit(int cle) { Produit p=null; sql=”SELECT * FROM produit WHERE ...”; if(...) { type=rs.getString(“type”); if(type.equals(“cd”)) { p=new CD(); p.load(rs); } } return p; }
  • 34. Factory modèle à 2 tables public static Produit getProduit(int cle) { Produit p=null; p=new CD(); if(!p.load(rs)) { p=new Livre(); On ne peut que faire des if(!p.load(rs)) tests en cascade { ... } else p=null; } return p; }
  • 35. Factory modèle à 3 tables public static Produit getProduit(int cle) { Produit p=null; sql=”SELECT * FROM produit WHERE ...”; if(...) { type=rs.getString(“type”); if(type.equals(“cd”)) { p=new CD(); p.load(rs); C’est dans chacune des } méthodes “load()” que l’on va faire } une jointure entre les tables ‘mère’ return p; et ‘fille’ }
  • 36. Hibernate Persistence d’objet en Java
  • 37. • • Rendre un objet persistant Pour rendre un objet persistant, il suffit de le lier à la session • La clé pourra éventuellement être générée automatiquement, et délivrée par save() : • • session.save(objet); Long cle=(Long)session.save(objet); • (clé déclarée assigned dans le HBM) Cette clé sera également dans objet.getRef()
  • 38. Sauvegarde par saveOrUpdate • • • Si la clé a été renseignée dans l’objet : • • Si la clé existe en base : UPDATE Si la clé n’existe pas : INSERT Si la clé n’a pas été renseignée : INSERT Si l’objet existe en base et n’a pas été modifié en mémoire : pas de requête générée
  • 39. Chargement d’un objet Client c=(Client)session.load(Client.class,new Long(12)); • ou : Client c=new Client();
 session.load(c,new Long(12)); • version sans lancement d’exception (renvoie null si l’objet n’existe pas) Client c=
 (Client)session.get(Client.class,new Long(12));
 if(c==null)
 c=new Client();
  • 40. Requêtage HQL Query q=session.createQuery(“...”);
 q.setString(0,”..”);
 q.setInt(1,”...”);
 List l=q.list(); // émission de la requête • S’il n’y a qu’un résultat : Client c=(Client)q.uniqueResult();
  • 41. Paramètres d’une requête • Par numéro : FROM Client WHERE nom=? AND age=? q.setString(0,”Dupont”); // commence à 0 • Par nom : FROM Client WHERE nom=:nom AND age=:age q.setString(“nom”,”Dupont”); • Listés : FROM Client WHERE nom IN (:liste) q.setParameterList(“liste”,unTableau);
  • 42. Récupération plusieurs objets d’un coup Query q = sess.createQuery(! "SELECT facture,client FROM Facture facture 
 JOIN Client facture.client client");
 List l=q.list();
 Iterator it=l.iterator();! ! while ( it.hasNext() ) {! Object[] tuple = (Object[]) it.next();! Facture f= tuple[0];! Client c = tuple[1];! ....! }
  • 43. Association N-1 unidirectionnelle <class name="Item">! <id name="ref" column="refitem">! <generator class="native"/>! </id>
 <many-to-one name=”prod” class=”Produit”>! <column="refprod" ! not-null="true"/>
 </many-to-one>! </class>! ! <class name="Produit">! <id name="ref" column="refprod">! <generator class="native"/>! </id>! </class> create table Item ( 
 refitem bigint not null primary key
 refprod bigint not null )! create table Produit ( 
 refprod bigint not null primary key) public class Item ( 
 private Long ref;
 private Produit prod;! )! public class Produit ( ! private Long ref;
 )
  • 44. Association 1-1 unidirectionnelle create table Client ( 
 <class name="Client">! refcli bigint not null primary key
 <id name="ref" column="refcli">! refpanier bigint not null )! <generator class="native"/>! create table Panier ( 
 </id>
 <many-to-one name=”panier” class=”Panier”>! refpanier bigint not null primary key) <column="refpanier"
 unique=”true” ! not-null="true"/>
 </many-to-one>! </class>! ! <class name="Panier">! <id name="ref" column="refpanier">! <generator class="native"/>! </id>! </class> public class Client ( 
 private Long ref;
 private Panier panier;! )! public class Panier ( ! private Long ref;
 )
  • 45. Association 1-N unidirectionnelle <class name="Client">! <id name="ref" column="refclient">! <generator class="native"/>! </id>! <set name="factures">! <key column="refclient" ! not-null="true"/>! <one-to-many class="Facture"/>! </set>! </class>! ! <class name="Facture">! <id name="ref" column="reffacture">! <generator class="native"/>! </id>! </class> create table Client ( 
 refclient bigint not null primary key )! create table Facture ( 
 reffacture bigint not null primary key,
 refclient bigint not null ) public class Client ( 
 private Long ref;
 private List factures;! )! public class Facture ( ! private Long ref;
 )
  • 46. Représentation d’héritage avec une table <class name="Produit" table="produit" abstract=”true” discriminator-value=”-”>! ! <id name="ref" column="ref">! <generator class="native"/>! </id>! <discriminator column="type" type="character"/>! ! create table produit (! ref BIGINT not null,! <subclass name="Livre" discriminator-value="L">! type CHAR(1) not null,! <property name="nbpages"/>! titre VARCHAR(255),! </subclass>! duree FLOAT,! maisondisque VARCHAR(255),! <subclass name="CD" discriminator-value="C">! nbpages INTEGER,! <property name="duree"/>! primary key (ref)! <property name="maisondisque"/>! </subclass>! ) <property name="titre"/>! 
 ! ! </class>
  • 47. Représentation d’héritage avec plusieurs tables ! ! 
 ! create table produit (! <class name="Produit" table="produit" abstract=”true”>! ref BIGINT not null,! type CHAR(1) not null,! <id name="ref" column="refprod">! titre VARCHAR(255),! <generator class="native"/>! duree FLOAT,! </id>! <discriminator column="type" type="character"/>! maisondisque VARCHAR(255),! nbpages INTEGER,! <property name="titre"/>! primary key (ref)! )! <join-subclass name="CD" table="cd">! ! <key column="refprod"/>! create table cd (! <property name="maisondisque"/>! </subclass>! ref BIGINT not null,! maisondisque VARCHAR(255),! </class> primary key (ref)! )