• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
JAVA, JDBC et liaison base de données
 

JAVA, JDBC et liaison base de données

on

  • 2,016 views

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

Statistics

Views

Total Views
2,016
Views on SlideShare
2,015
Embed Views
1

Actions

Likes
1
Downloads
28
Comments
1

1 Embed 1

http://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    JAVA, JDBC et liaison base de données JAVA, JDBC et liaison base de données Presentation Transcript

    • Java et bases de données JDBC - Hibernate Version du 05/12/2013
    • 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)
    • 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
    • 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; } }
 }
    • 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) ; }
    • 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
    • ! 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) {
 }
    • 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);
    • Exemple de parcours d’un ResultSet while(rs.next())
 {
 int num=rs.getInt(“num”);
 String titre=rs.getString(“titre”);
 }
    • 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(...)
    • • 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
    • 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
    • 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);
    • 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
    • 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();
    • 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
    • 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);! }
    • 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)
    • 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...
    • 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()
    • 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
    • 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);
 }
    • 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 ?
    • 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 } }
    • 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); } }
    • 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); } }
    • 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); } }
    • 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
    • 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
    • • 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
    • • 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
    • 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);
    • 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; }
    • 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; }
    • 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’ }
    • Hibernate Persistence d’objet en Java
    • • • 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()
    • 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
    • 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();
    • 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();
    • 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);
    • 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];! ....! }
    • 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;
 )
    • 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;
 )
    • 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;
 )
    • 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>
    • 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)! )