Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Du 22 au 24 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Développement informatique
  3. JDBC
Extrait - Développement informatique Apprenez à concevoir avant de programmer
Extraits du livre
Développement informatique Apprenez à concevoir avant de programmer
3 avis
Revenir à la page d'achat du livre

JDBC - Mapping Objet/Relationnel

Objectifs du chapitre

  • Développer des applications qui accèdent à une base de données relationnelle.

  • Développer les classes nécessaires au mapping objet relationnel (il s’agit d’établir une correspondance entre les tables d’une base de données relationnelle et les objets utilisés pour accéder à la base).

Définition

L’API JDBC (Java DataBase Connectivity) est un ensemble de classes et d’interfaces Java qui permettent l’accès aux données.

Bien que l’API JDBC permette l’accès à toute source de données, elle est essentiellement utilisée pour accéder aux bases de données relationnelles.

Communication Java - Base de données

1. Pilotes (drivers) JDBC

Pour se connecter à une base de données, JDBC a besoin de classes particulières écrites par l’éditeur de la base de données. Ces classes sont regroupées dans un pilote (driver). C’est un fichier .jar (Java archive).

L’API JDBC fournit des interfaces que les pilotes doivent obligatoirement implémenter. 

Cela présente deux avantages :

  • Les interfaces exposent les méthodes que l’on peut utiliser.

  • Il est possible d’utiliser ces méthodes sans connaître le nom de la classe correspondante du pilote. Ce nom est différent selon l’éditeur de base de données.

2. Schéma de communication

images/02143a.png

Travailler avec JDBC

1. Exécution d’une requête SQL de type SELECT

Écrire un programme Java qui accède à une base de données nécessite de :

  • Charger le pilote de la base de données utilisée.

  • Établir une connexion à la base. Il faut fermer la connexion après utilisation.

  • Créer un objet Statement (objet de traitement). Il faut fermer le Statement après utilisation.

  • Exécuter des requêtes SQL

  • Si la requête est un SELECT, elle retourne un objet ResultSet, qui contient les lignes et les colonnes sélectionnées. Il faut fermer le ResultSet après utilisation.

2. Structure générale du programme pour une requête SELECT

Le "squelette" de programme suivant montre comment fermer à coup sûr la connexion, le Statement et le ResultSet. Chaque ouverture ou création réussie est suivie d’un bloc try avec un finally de fermeture des objets :


Charger le pilote de la base de données 
 
Etablir une connexion à la base (objet Connection) 
try 
{ 
    Créer un objet Statement 
    try 
    { 
        Exécuter un SELECT : il retourne un objet ResultSet 
        try 
        { 
            Utiliser le ResultSet 
        } 
        finally 
        { 
            Fermer le ResultSet 
        } 
    } 
    finally 
    { 
        fermer le Statement 
    } 
} 
finally 
{ 
    Fermer la connexion 
}
 

Quand on ferme la connexion, le Statement et le ResultSet restent référencés, mais inutilisables. Il est important de fermer le ResultSet et le Statement pour récupérer la place occupée par ces objets devenus inutiles.

3. Exemple : base de données utilisée

  • Le système de gestion de base de données utilisé est MySQL.

  • La base de données est nommée "gnmi".

  • Le nom d’utilisateur et le mot de passe sont...

Présentation des classes utilitaires

Dans le package utilitairesMG.jdbc se trouvent des classes qui peuvent faciliter le développement.

1. JeuResultat

a. Classe JeuResultat

La méthode executeQuery() de l’interface Statement renvoie un objet de type ResultSet.

Un ResultSet est lié à la connexion. Quand on ferme la connexion, on perd le ResultSet. Or, il est souvent intéressant de conserver les résultats lus après avoir fermé la connexion.

La classe JeuResultat permet de recopier les informations du ResultSet. On peut ensuite fermer la connexion, tout en ayant préservé les valeurs lues.

Cette recopie organise les données lues en deux collections :

  • une collection d’objets Colonne (la classe Colonne est celle du package utilitairesMG.divers)

  • une collection de lignes (Vector<Vector<Object>>)

Un des constructeurs de la classe JeuResultat prend en paramètre un ResultSet, qu’il recopie dans les deux collections.

Grâce à cette organisation des données, l’utilisation de la classe JeuResultat est plus agréable et plus simple que celle du ResultSet. Mais on a le droit d’aimer les next() !


public class JeuResultat implements java.io.Serializable 
{ 
    private Vector<Colonne> colonnes; 
    private Vector<Vector<Object>> lignes; 
 
    public JeuResultat() 
    { 
    } 
 
    public JeuResultat(ResultSet rs) throws SQLException 
    { 
        . . . 
    } 
 
    . . . 
     
    public Vector<Colonne> getColonnes() 
    { 
        return colonnes; 
    } 
 
    public Vector<Vector<Object>> getLignes() 
    { 
        return lignes; 
    } 
 
    . . . 
}
 

b. Exécution d’une requête SQL de type SELECT avec JeuResultat


public class TestJdbcSqlJeuResultat 
{ 
    public static void main(String args[]) throws IOException 
    { 
        Connection connexion; 
        Statement...

Travail pratique : Projet GestionContactJdbc - Version 1

1. Objectif

  • Utiliser JDBC pour accéder à une base de données.

  • Modifier le Modèle de l’application GestionContactLocal pour permettre cet accès. Adapter le Contrôleur. Conserver la Vue inchangée.

2. Architecture du projet : 2 tiers

images/02146a.png

3. Sujet

Reprendre l’application GestionContactLocal du chapitre JTable - DAO - MVC.

  • Modifier la classe ContactDAO pour lire les données "Contact" dans la table CONTACT de la base de données gnmi (utilisateur UTIL_BIP, mot de passe x).

  • Si la lecture de la base de données provoque une exception, afficher le message d’erreur dans une boîte de dialogue (JOptionPane).

  • À la fermeture de la fenêtre interne contact, ne rien changer par rapport au projet GestionContactLocal. Ne pas reporter les modifications dans la base de données.

4. Conception

Compléter le diagramme de séquence de l’application GestionContactLocal.

5. Programmation

Modifier les classes ContactDAO et Controleur.

Toutes les classes de la vue sont utilisables sans modification.

6. GestionContactJdbc - Version 1 : proposition de correction

a. Diagramme de séquence

images/captureP605.PNG

Traitement des exceptions :

La lecture de données dans la base peut échouer pour diverses raisons, techniques ou logicielles (problèmes d’autorisations, requête SQL incorrecte, serveur hors service...). La méthode executeQuery() peut émettre une exception de type SQLException.

Qui doit être informé de ces erreurs ? C’est l’utilisateur de l’application. C’est pourquoi le contrôleur prévoit une alternative...

JDBC : compléments

1. Table utilisée dans les exemples

a. Script SQL de création de la table EMPLOYE


drop table EMPLOYE; 
 
create table EMPLOYE 
( 
    EMPNUM                          smallint primary key not null, 
    EMPNOM                          varchar(20) null, 
    EMPSAL                          dec(9,2) null, 
    EMPDAT                          datetime null 
); 
 
create unique index EMPLOYE_PK on EMPLOYE(EMPNUM);
 

b. Script SQL de remplissage de la table EMPLOYE


delete from employe; 
insert into employe values(1, 'Perdreau', NULL, '2016/04/25'); 
insert into employe values(4, 'Pie grièche', 2214, NULL); 
insert into employe values(10, 'Pivert', 1811, '2015/11/05'); 
 
select * from employe;
 

2. Exécution de requêtes INSERT et DELETE


public class TestInsert 
{ 
    public static void main(String args[]) throws IOException 
    { 
        . . . 
        try 
        { 
            Class.forName("com.mysql.jdbc.Driver"); 
 
            base = new BaseDeDonnees( 
                "jdbc:mysql://localhost/gnmi?user=util_bip&password=x"); 
            accesBase = new AccesBase(base); 
 
            try 
            { 
                accesBase.getConnection(); 
 
                try 
                { 
                    requeteSQL = "DELETE FROM EMPLOYE";  
                    codeRetour...

Le Mapping Objet/Relationnel

1. Exposé du problème à résoudre

Il s’agit d’effectuer des entrées/sorties entre une base de données relationnelle et des objets placés en mémoire.

Voici un schéma général des entrées/sorties (lectures/écritures) :

images/02148a.png
  • Lire des informations consiste à transférer des informations du disque dans une zone de mémoire prévue pour les réceptionner. Cette zone de mémoire doit être assez grande pour contenir les informations lues.

  • Écrire des informations consiste à recopier les informations contenues dans la zone de mémoire sur le disque dur.

Dans le cas d’une base de données relationnelle, les données stockées sur le disque sont organisées sous forme de tables. Chaque table est composée de colonnes et de lignes.

Exemple

Table CONTACT

images/02148b.png

Cette table contient cinq colonnes : NUMERO, NOM, ADRESSE, CODE_POSTAL, VILLE.

Elle contient trois lignes correspondant à des contacts : 100, 101, 102.

Lire une ligne de la table nécessite de réserver un espace en mémoire. Dans le cas d’un langage-objet, il faut instancier un objet d’une classe.

Le schéma UML suivant indique que la classe Contact possède des propriétés correspondant à chaque colonne de la table CONTACT : numero, nom, adresse, codePostal et ville.

images/02148c.png

Le numero, qui identifie de façon unique le contact, est appelé clé primaire.

Voici le code Java de la classe Contact :


public class Contact 
{ ...

Travail pratique : Projet Mapping

1. Objectif

Trouver une démarche systématique de conception et d’écriture des classes nécessaires au mapping objet/relationnel.

2. Sujet

  • Concevoir et écrire les classes Contact, ContactDAO, Secteur, SecteurDAO, Versement, VersementDAO, nécessaires pour lire et écrire des objets Java à partir d’une base de données relationnelle, dont la description est donnée par son MCD.

  • On peut commencer par concevoir les classes Contact et ContactDAO du projet, puis généraliser aux secteurs et versements.

  • Dans la classe Contact, il s’agit de lire (get) et modifier (set) toutes les propriétés de la classe.

  • Dans la classe ContactDAO, il s’agit de prévoir tous les accès à la base (select, update, insert, delete) et quelques méthodes de génération de listes d’objets Contact.

3. Documents joints

Les sections suivantes présentent :

  • le MCD du projet Mapping

  • le diagramme de classes du projet Mapping

  • le contrôleur d’une application de test qui utilise les classes à développer

Dans le package utilitairesMG.divers existe une classe Conversion qui possède une méthode chaineSQL() qui permet de convertir une chaîne de caractères au format SQL (problème des simples quotes). Il y a aussi une méthode dateSQL()

a. Modèle Conceptuel de Données (MCD) du projet Mapping

images/021411a.png
  • Un secteur peut avoir plusieurs contacts.

  • Un contact appartient à un secteur et peut avoir plusieurs versements.

  • Un versement appartient à un contact.

b. Diagramme de classes (UML) du projet Mapping

images/021411b.png

Ce diagramme représente les mêmes règles de gestion que le MCD. Attention, entre Merise et UML, les cardinalités sont inversées !

Le modèle conceptuel de données de Merise représente les tables de la base de données. Le diagramme UML représente les objets en mémoire. Cette différenciation est pratique et visuelle. Il est bien sûr possible de tout représenter en UML. Mais puisque nous avons les deux représentations, autant en profiter...

c. Contrôleur de l’application de test


public class Controleur 
{ 
    private static BaseDeDonnees base; 
    private static AccesBase...

Travail pratique : Projet GestionContactJdbc

1. Objectifs

  • Utiliser les packages des classes développées dans le TP Mapping.

  • Enregistrer les modifications dans la base de données.

2. Sujet

  • Modifier l’application "GestionContactJdbc - version 1" afin de permettre l’enregistrement des modifications des contacts dans la base de données lors de la fermeture de la fenêtre interne des contacts.

  • Remplacer les classes Contact et ContactDAO par celles des packages metierMapping et daoJdbcMapping.

  • Le package metierMapping contient les classes Contact, Secteur, Versement.

  • Le package daoJdbcMapping contient les classes ContactDAO, SecteurDAO, VersementDAO.

  • Transmettre la liste des Secteurs à la fenêtre interne des contacts pour adapter la liste déroulante de saisie du code secteur…

images/021412a.png

3. GestionContactJdbc : Proposition de correction

a. Classe Controleur


public class Controleur 
{ 
    . . . 
 
    public static void main(String args[]) 
    { 
        . . . 
        contactDAO = new ContactDAO(accesBase);  
        secteurDAO = new SecteurDAO(accesBase); 
        . . . 
    } 
 
    public static void demandeContacts() 
    { 
        Vector<Contact> listeContacts; 
        Vector<Colonne> listeColonnes;  
        Vector<Secteur> listeSecteurs; 
 
        try 
        { 
            accesBase.getConnection(); 
 
            try 
            { 
                listeContacts = contactDAO.lireListe(); 
                listeColonnes = contactDAO.getListeColonnes();  
                listeSecteurs = secteurDAO.lireListe(); 
 
                ...