47
Java et bases de données JDBC - Hibernate Version du 05/12/2013

JAVA, JDBC et liaison base de données

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: JAVA, JDBC et liaison base de données

Java et bases de donnéesJDBC - Hibernate

Version du 05/12/2013

Page 2: JAVA, JDBC et liaison base de données

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)

Page 3: JAVA, JDBC et liaison base de données

Process de requétage1. 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

Page 4: JAVA, JDBC et liaison base de données

1 - Chargement du driver

import java.sql.*; !class Cnx { public Cnx() { try { Class.forName("com.mysql.jdbc.Driver").newInstance(); } catch (ClassNotFoundException e) { System.out.println("Driver spécifié non trouvé"); throw e; } }}

Accès direct au driver par une chaîne de

caractères

On utilise les prototypes

de java.sql

Page 5: JAVA, JDBC et liaison base de données

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) ; }

Page 6: JAVA, JDBC et liaison base de données

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

Page 7: JAVA, JDBC et liaison base de données

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) {}

Page 8: JAVA, JDBC et liaison base de données

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);

Page 9: JAVA, JDBC et liaison base de données

Exemple de parcours d’un ResultSet

while(rs.next()) { int num=rs.getInt(“num”); String titre=rs.getString(“titre”); }

Page 10: JAVA, JDBC et liaison base de données

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(...)

Page 11: JAVA, JDBC et liaison base de données

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

Page 12: JAVA, JDBC et liaison base de données

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

Page 13: JAVA, JDBC et liaison base de données

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);

Page 14: JAVA, JDBC et liaison base de données

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

Page 15: JAVA, JDBC et liaison base de données

Exemple de PreparedStatement

// Création du Statement

PreparedStatement phrase= dbC.prepareStatement(

 " INSERT into TABLE (chaine, entier, reel) VALUES (?,?,?) "); // Mise en place des paramètres phrase.setString(1, "uneChaine"); phrase.setInt(2, 56); phrase.setDouble(3, 3.314456); // Exécution de la requête phrase.executeUpdate();

Liste de paramètres

Page 16: JAVA, JDBC et liaison base de données

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

Page 17: JAVA, JDBC et liaison base de données

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);!}

Page 18: JAVA, JDBC et liaison base de données

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)

Page 19: JAVA, JDBC et liaison base de données

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...

Page 20: JAVA, JDBC et liaison base de données

Structure de la classe User

• C’est un objet CRUD (Create/Read/Update/Delete)

• Exemple de création/enregistrement : User u=new User(); u.setNom(“.....”); ... u.insert();

User

login password nom

select(login) insert() update() delete()

Page 21: JAVA, JDBC et liaison base de données

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

Page 22: JAVA, JDBC et liaison base de données

Constructeurs de Userpublic 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); }

Page 23: JAVA, JDBC et liaison base de données

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 ?

Page 24: JAVA, JDBC et liaison base de données

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 } }

Page 25: JAVA, JDBC et liaison base de données

Remplissage “procédural”

public void rech(String texte) { sql=”SELECT * FROM produit WHERE ...”; while(...) { Produit p=new Produit(); p.nom=rs.getString(“nom”); ... liste.add(p); } }

Problème : on gère la lecture d’un produit en dehors de la classe Produit

Page 26: JAVA, JDBC et liaison base de données

Remplissage “objet”public void rech(String texte) { sql=”SELECT cle FROM produit WHERE ...”; while(...) { cle=rs.getInt(“cle”); Produit p=new Produit(); p.load(cle); liste.add(p); } }

Problème : On génère un grand nombre de requête (N+1 requêtes, N étant le nombre de produits)

Page 27: JAVA, JDBC et liaison base de données

Solution mixtepublic void rech(String texte) { sql=”SELECT * FROM produit WHERE ...”; while(...) { cle=rs.getInt(“cle”); Produit p=new Produit(); p.load(rs); liste.add(p); } }

Dans cette solution, on passe à Produit directement l’objet “rs” afin de traiter la requête à la source

Page 28: JAVA, JDBC et liaison base de données

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 pour la classe mère

• 1 table par classe fille

Page 29: JAVA, JDBC et liaison base de données

Modèle à une table• A partir d’une hiérarchie de classe Produit ->

Cd ou Livre :

Table produit : -refprod -type -nom -prix -dureecd -nbpageslivres La table contient à la

fois les infos du CD, et celles du livre

Cette solution est valable si CD et Livre ont peu

de données divergentesLe type est encodé dans un

champ

Page 30: JAVA, JDBC et liaison base de données

Une table par classe fille sans factorisation

• A partir d’une hiérarchie de classe Produit -> Cd ou Livre :

La table Livre contient toutes les données

Cette solution facilite les requêtes mais complique les recherches

inter-catégoriesTable CD : -refprod -type -nom -prix -dureecd

Table Livre : -refprod -type -nom -prix -nbpages

Page 31: JAVA, JDBC et liaison base de 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 -type -nom -prix

La table Livre contient uniquement les données

propres au livre

Cette solution concilie factorisation et particularité des types de produits

Table CD : -refprod -dureecd

Table Livre : -refprod -nbpages

Page 32: JAVA, JDBC et liaison base de données

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);

Page 33: JAVA, JDBC et liaison base de données

Factory modèle à 1 tablepublic 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; }

Page 34: JAVA, JDBC et liaison base de données

Factory modèle à 2 tablespublic static Produit getProduit(int cle) { Produit p=null; p=new CD(); if(!p.load(rs)) { p=new Livre(); if(!p.load(rs)) { ... } else p=null; } return p; }

On ne peut que faire des tests en cascade

Page 35: JAVA, JDBC et liaison base de données

Factory modèle à 3 tablespublic 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; }

C’est dans chacune des méthodes “load()” que l’on va faire une jointure entre les tables ‘mère’

et ‘fille’

Page 36: JAVA, JDBC et liaison base de données

HibernatePersistence d’objet en Java

Page 37: JAVA, JDBC et liaison base de données

Rendre un objet persistant

• Pour rendre un objet persistant, il suffit de le lier à la session

• session.save(objet);

• La clé pourra éventuellement être générée automatiquement, et délivrée par save() :

• Long cle=(Long)session.save(objet);

• (clé déclarée assigned dans le HBM)

• Cette clé sera également dans objet.getRef()

Page 38: JAVA, JDBC et liaison base de données

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

Page 39: JAVA, JDBC et liaison base de données

Chargement d’un objetClient 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();

Page 40: JAVA, JDBC et liaison base de données

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();

Page 41: JAVA, JDBC et liaison base de données

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);

Page 42: JAVA, JDBC et liaison base de données

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];! ....!}

Page 43: JAVA, JDBC et liaison base de données

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;)

Page 44: JAVA, JDBC et liaison base de données

Association 1-1 unidirectionnelle

<class name="Client">! <id name="ref" column="refcli">! <generator class="native"/>! </id> <many-to-one name=”panier” class=”Panier”>! <column="refpanier" unique=”true” ! not-null="true"/> </many-to-one>!</class>!!<class name="Panier">! <id name="ref" column="refpanier">! <generator class="native"/>! </id>!</class>

create table Client ( refcli bigint not null primary key refpanier bigint not null )!create table Panier ( refpanier bigint not null primary key)

public class Client ( private Long ref; private Panier panier;!)!public class Panier ( ! private Long ref;)

Page 45: JAVA, JDBC et liaison base de données

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;)

Page 46: JAVA, JDBC et liaison base de données

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"/>!! <property name="titre"/>! <subclass name="Livre" discriminator-value="L">! <property name="nbpages"/>! </subclass>!! <subclass name="CD" discriminator-value="C">! <property name="duree"/>! <property name="maisondisque"/>! </subclass>!! </class>

create table produit (! ref BIGINT not null,! type CHAR(1) not null,! titre VARCHAR(255),! duree FLOAT,! maisondisque VARCHAR(255),! nbpages INTEGER,! primary key (ref)!)

Page 47: JAVA, JDBC et liaison base de données

Représentation d’héritage avec plusieurs tables

<class name="Produit" table="produit" abstract=”true”>!! <id name="ref" column="refprod">! <generator class="native"/>! </id>! <discriminator column="type" type="character"/>!! <property name="titre"/>! <join-subclass name="CD" table="cd">! <key column="refprod"/>! <property name="maisondisque"/>! </subclass>!! </class>

create table produit (! ref BIGINT not null,! type CHAR(1) not null,! titre VARCHAR(255),! duree FLOAT,! maisondisque VARCHAR(255),! nbpages INTEGER,! primary key (ref)!)!!create table cd (! ref BIGINT not null,! maisondisque VARCHAR(255),! primary key (ref)!)