0
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...
Process de requétage
1. Chargement du driver	

2. Connexion à la base	

3. Création de Statement	


•
•

Envoi de la requê...
1 - Chargement du
driver

On utilise
les prototypes
de java.sql

import java.sql.*;

!

class Cnx
Accès direct au driver
{...
2 - Connexion à la base
try
{
dbC=DriverManager.getConnection
("jdbc:mysql://localhost/Bibliotheque","user","passwd");
}
c...
Comment récupérer la
connexion ?
•

Il faut éviter à tout prix de relancer X fois la
procédure “chargement driver / connex...
!

3 - Création de
Statement

try

{
// dbC est l'instance de connexion
Statement st=cnx.createStatement();


// Exemple d...
4 - Exploitation des
résultats
•
•

Après le SELECT : Exploitation du ResultSet	

Accès aux colonnes par :	


•

Index (à ...
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 :	


•
•

pre...
•

5 - Fin de connexion
Il faut penser à fermer tous les objets	

rs.close();

st.close();

cnx.close();	


•

Il est impo...
Récupération d’une clé
générée

•
•

Certaines tables génèrent automatiquement
leur clé lors d’un INSERT	


•

(auto_incre...
Récupération de la clé
String req=”INSERT …“;
st.executeUpdate(sql);
!

// Récupération avec
Statement.getGeneratedKeys()
...
Les statement préparés
•

Permet de faciliter l’écriture de requêtes
complexes	


•

Stockées dans le SGBD, seuls les para...
Exemple de
PreparedStatement
// Création du Statement
PreparedStatement phrase= dbC.prepareStatement(
 " INSERT into TABLE...
Intérêts du
PreparedStatement
•

Légèrement plus efficace (pré-exécution sur
le SGBD)	


•

Evite des problèmes de syntaxe	...
Traitements batchs
Connection connection = ... ; !
Statement statement = connection.createStatement();!
if(connection.getM...
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...
Exemple d’intégration
d’appels à la base
•
•

Une classe User utilisée dans un site Web	

On peut :	


•
•

Se connecter a...
Structure de la classe
User
•
•

User

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

login	

password	

Exemple de cr...
Procédure de login
•

•

Comment faire à la fois :	


•
•
•

Contrôler si un login/pass est correct	

Charger les données ...
Constructeurs de User

public class User()

{

public User(String login, String pwd) 

throws UserInexistantException()

{...
Exploitation de
liaisons 1-N
•

En objet : c’est un attribut qui contient des
instances d’autres objets	


•

En SGBD : c’...
Exemple de liste en
objet
public class Catalogue	

{	

private ArrayList<Produit> liste;	

!

}

public void rech(String t...
Remplissage
“procédural”
public void rech(String texte)	

{	

sql=”SELECT * FROM produit WHERE ...”;	

while(...)	

{	

Pr...
Remplissage “objet”
public void rech(String texte)	

{	

sql=”SELECT cle FROM produit WHERE ...”;	

while(...)	

{	

Probl...
Solution mixte
public void rech(String texte)	

{	

sql=”SELECT * FROM produit WHERE ...”;	

while(...)	

{	

Dans cette s...
L’héritage dans un
modèle relationnel
•

Problématique : il n’est pas possible de définir
directement une structure d’hérit...
Modèle à une table
•

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

Le type est
encodé dans un
champ

Tabl...
•

Une table par classe fille
sans factorisation

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

1 table par classe fille +
1 table pour classe mère

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

Table...
Lecture base d’une
classe polymorphe
•

On passe par une Factory qui va délivrer
suivant les cas une instance de CD, de Li...
Factory modèle à 1 table
public static Produit getProduit(int cle)	

{	

Produit p=null;	

sql=”SELECT * FROM produit WHER...
Factory modèle à 2 tables
public static Produit getProduit(int cle)	

{	

Produit p=null;	

p=new CD();	

if(!p.load(rs))	...
Factory modèle à 3 tables
public static Produit getProduit(int cle)	

{	

Produit p=null;	

sql=”SELECT * FROM produit WHE...
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 éven...
Sauvegarde par
saveOrUpdate
•
•
•

Si la clé a été renseignée dans l’objet :	


•
•

Si la clé existe en base : UPDATE	

S...
Chargement d’un objet
Client c=(Client)session.load(Client.class,new Long(12));	


•

ou :	

Client c=new Client();

sessi...
Requêtage HQL
Query q=session.createQuery(“...”);

q.setString(0,”..”);

q.setInt(1,”...”);

List l=q.list(); // émission ...
Paramètres d’une
requête
• Par numéro :	

FROM Client WHERE nom=? AND age=?	

q.setString(0,”Dupont”); // commence à 0	


...
Récupération plusieurs
objets d’un coup
Query q = sess.createQuery(!
"SELECT facture,client FROM Facture facture 

JOIN Cl...
Association N-1
unidirectionnelle
<class name="Item">!
<id name="ref" column="refitem">!
<generator class="native"/>!
</id>...
Association 1-1
unidirectionnelle
create table Client ( 

<class name="Client">!
refcli bigint not null primary key

<id n...
Association 1-N
unidirectionnelle
<class name="Client">!
<id name="ref" column="refclient">!
<generator class="native"/>!
...
Représentation
d’héritage avec une table
<class name="Produit" table="produit" abstract=”true” discriminator-value=”-”>!

...
Représentation d’héritage
avec plusieurs tables
!

!



!

create table produit (!
<class name="Produit" table="produit" a...
Upcoming SlideShare
Loading in...5
×

JAVA, JDBC et liaison base de données

3,419

Published on

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

1 Comment
2 Likes
Statistics
Notes
No Downloads
Views
Total Views
3,419
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
131
Comments
1
Likes
2
Embeds 0
No embeds

No notes for slide

Transcript of "JAVA, JDBC et liaison base de données"

  1. 1. Java et bases de données JDBC - Hibernate Version du 05/12/2013
  2. 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. 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. 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. 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. 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. 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. 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. 9. Exemple de parcours d’un ResultSet while(rs.next())
 {
 int num=rs.getInt(“num”);
 String titre=rs.getString(“titre”);
 }
  10. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 36. Hibernate Persistence d’objet en Java
  37. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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)! )
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×