Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
Java (API)
Par cysboy
www.openclassrooms.com
Sommaire
Sommaire ........................................................................................................................................... 2
Partager .............................................................................................................................................. 1
Programmation en Java (API) ............................................................................................................ 3
Partie 1 : Java DataBase Connectivity ................................................................................................ 4
En premier : la base de données ...................................................................................................................................... 4
Une base de données, quésaco ? .............................................................................................................................................................................. 4
Laquelle utiliser ........................................................................................................................................................................................................... 5
Installation de PostgreSQL .......................................................................................................................................................................................... 5
PostgreSQL ..................................................................................................................................................................... 10
Préparer sa BDD ....................................................................................................................................................................................................... 10
Créer la BDD ............................................................................................................................................................................................................. 11
Créer ses tables ........................................................................................................................................................................................................ 13
Se connecter à sa BDD ................................................................................................................................................... 20
Faisons le point ......................................................................................................................................................................................................... 21
Connexion ! Es-tu là ? ............................................................................................................................................................................................... 23
Fouiller dans sa BDD ...................................................................................................................................................... 25
Le couple Statement - ResultSet .............................................................................................................................................................................. 26
Comment ça fonctionne ............................................................................................................................................................................................ 28
Entraînons-nous ........................................................................................................................................................................................................ 30
Allons un peu plus loin .................................................................................................................................................... 36
Statement .................................................................................................................................................................................................................. 36
Les requêtes préparées ............................................................................................................................................................................................ 36
ResultSet 2 : le retour ................................................................................................................................................................................................ 39
Après la lecture : l'édition ................................................................................................................................................ 42
Modifier des données ................................................................................................................................................................................................ 43
Statement, toujours plus fort ..................................................................................................................................................................................... 45
Gérer les transactions manuellement ....................................................................................................................................................................... 47
N'avoir qu'une instance de sa connexion ........................................................................................................................ 50
Pourquoi se connecter qu'une seule fois ? ............................................................................................................................................................... 51
Le pattern singleton ................................................................................................................................................................................................... 51
Le singleton dans tous ces états ............................................................................................................................................................................... 54
TP : un testeur de requête ............................................................................................................................................... 57
Cahier des charges ................................................................................................................................................................................................... 58
Quelques captures d'écran ....................................................................................................................................................................................... 58
Correction .................................................................................................................................................................................................................. 58
Le pattern DAO (1/2) ....................................................................................................................................................... 62
Avant toute chose ...................................................................................................................................................................................................... 63
Le pattern DAO : définition ........................................................................................................................................................................................ 70
Contexte .................................................................................................................................................................................................................... 70
Le pattern DAO ......................................................................................................................................................................................................... 70
Premier test ............................................................................................................................................................................................................... 78
Le pattern DAO (2/2) ....................................................................................................................................................... 80
Le pattern factory ...................................................................................................................................................................................................... 81
Fabriquer vos DAO .................................................................................................................................................................................................... 82
D'une usine à une multinationale .............................................................................................................................................................................. 85
www.openclassrooms.com
Sommaire 3/93
Le tutoriel que vous êtes en train de lire est en bêta-test. Son auteur souhaite que vous lui fassiez part de vos
commentaires pour l'aider à l'améliorer avant sa publication officielle. Notez que le contenu n'a pas été validé par
l'équipe éditoriale du Site du Zéro.
Par cysboy
Nous allons voir ce qu'il vous faut pour utiliser des bases de données, comment faire de la programmation réseau... Nous nous
baladerons aussi dans quelques frameworks (boîte à outils).
Tout ceci est présent dans le JDK, dans les API standards. Je vous propose d'en faire un tour d'horizon, le tout en partant de
ZérO, bien évidemment !
www.openclassrooms.com
Programmation en Java (API) 4/93
Dans cette partie nous allons voir comment interagir avec des bases de données via Java !
Il n'y a rien de compliqué puisque tous les objets dont vous aurez besoin existent déjà...
Nous allons donc voir à quoi sert une base de données, mais aussi en installer une afin de pouvoir illustrer la suite de cette
partie.
Allez ! Zou...
Une base de données, quésaco ?
Lorsque vous réalisez un logiciel, un site web, ou je ne sais quoi d'autre, vous êtes confrontés, à un moment ou un autre, à une
question : comment vais-je faire pour sauvegarder mes données ?
Les bases de données (ou BDD) sont une alternative sûre et pérenne.
Ce système de stockage des données existe depuis très longtemps et a fait ses preuves ! Ceux qui souhaiteraient en savoir plus
sur les BDD peuvent suivre ce lien.
Résumé à l'extrême, il s'agit d'un système de fichiers qui contiennent les données de votre application. Mais ces fichiers sont
totalement transparents pour l'utilisateur d'une base de données, donc, totalement transparents pour VOUS !
Ces données sont ordonnées par "tables", c'est-à-dire par regroupements de plusieurs valeurs.
C'est vous qui allez créer vos propres tables, en spécifiant quelles données vous souhaitez y intégrer.
En fait, imaginez qu'une base de données est une gigantesque armoire à tiroirs dont vous spécifiez les noms et qui contiendront
une multitude de fiches dont vous spécifierez aussi leur contenu !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 5/93
Dans cette base de données, nous avons deux tables : une qui a pour rôle de stocker des personnes avec noms, prénoms et
âges, et une table qui s'occupe de stocker des pays, avec leur nom et leur capitale !
Si je reprends ma comparaison de tout à l'heure, la BDD symbolise l'armoire, chaque table un tiroir et chaque ligne de chaque
table, une fiche de ce tiroir !
Ensuite, ce qui est formidable avec les BDD, c'est que vous pouvez les interroger en leur posant des questions via un langage.
Vous pouvez leur demander des trucs comme :
Le langage qui vous permet d'interroger des bases de données est le langage SQL, où, en français, "Langage de Requête
Structurées". Nous aurons l'occasion d'en faire un bref rappel lors du chapitre suivant...
Ainsi, grâce aux BDD, vos données sont stockées, classées par vos soins et identifiables facilement sans avoir à gérer notre
propre système de fichiers.
C'est vrai que c'est alléchant, mais comment fait-on pour s'en servir ? On doit télécharger quelque chose ?
PostgreSQL
MySQL
SQL Server
Oracle
Access
...
C'est à vous de faire votre choix en regardant sur le web ce que les utilisateurs en disent.
Sinon, il y a un comparatif intéressant, ici.
Pour le tuto sur JDBC, mon choix s'est porté sur PostgreSQL.
Alors continuons.
Installation de PostgreSQL
Vous pouvez télécharger une version de PosteSQL ici.
Celle-ci est pour Windows, mais pour les autres OS, vous pouvez faire un tour par-là.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 6/93
À partir de maintenant, si je ne vous spécifie pas de fenêtre particulière, vous pouvez laisser les réglages par défaut.
On vous demandera, par la suite, de saisir un mot de passe pour l'utilisateur, comme ceci :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 7/93
À la fin de la pré-installation, on vous demandera si vous voulez exécuter le "Stack Builder" ; ce n'est pas nécessaire, ça permet
juste d'installer d'autres logiciels en rapport avec PostgreSQL... Nous n'en avons pas besoin.
Normalement, le serveur est installé et je dirais même qu'il en est de même pour le SGBD !
Ah bon ?
Oui, regardez dans le menu "Démarrer" et allez dans "Tous les programmes", vous devriez avoir ceci dans l'encart
"PostgreSQL 8.3 " :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 8/93
Il y a deux exécutables qui permettent respectivement de lancer le serveur ou de l'arrêter et le dernier, pgAdmin III, c'est notre
SGBD !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 9/93
Nous reviendrons sur tout ceci, mais vous pouvez lire que votre serveur, nommé "SDZ", a une base de données appelée
"postgres" qui contient 0 table !
Simple et efficace !
Voilà, nous avons installé notre serveur, nous allons voir maintenant comment créer une base, des tables mais surtout faire un
bref rappel sur ce fameux langage SQL...
Pas de QCM pour ce chapitre, mais n'y prenez pas trop goût... Tout ceci ne durera pas...
Bon, rien de sorcier ici !
La plupart d'entre vous n'a peut-être rien vu de nouveau, mais il fallait partir de ZérO...
Dès le prochain chapitre, nous allons voir comment Java va "discuter" avec notre base de données...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 10/93
PostgreSQL
Alors, maintenant, nous allons aborder la prise en main de cet outil qu'est PostgreSQL !
Dans ce chapitre, nous verrons comment créer une base de données, des tables, ajouter des contraintes de clés et d'intégrités...
Enfin bref, tout ce dont vous allez avoir besoin pour suivre au mieux ce tutoriel. Ceci, bien sûr, sans rentrer dans les détails : c'est
un tuto sur JDBC, pas sur PostgreSQL ou sur SQL !
Déjà, les bases de données servent à stocker des informations, ça, vous le savez !
Mais ce que vous ignorez peut-être, c'est que, pour ranger correctement nos informations, nous allons devoir analyser celles-ci...
Ce tuto n'est pas non plus un tuto sur l'analyse combinée avec des diagrammes entités-associations... Dans le jargon, c'est ce
dont on se sert pour créer des BDD, enfin, pour organiser les informations (tables et contenu de tables) !
Nous allons juste poser un thème et nous ferons comme si vous saviez faire tout ça !
Pour ceux que la réalisation de modèles entités-associations intéressent, vous pouvez faire un tour ici.
Voilà : pour notre base de données, nous allons gérer une école, dont voici les caractéristiques :
Vous vous rendez compte qu'il y a beaucoup d'informations à gérer. Bon, en théorie, nous devrions faire un dictionnaire des
données, voir à qui appartient quelle donnée, poursuivre avec une modélisation façon MCD (Modèle Conceptuel de Données)
et simplifier le tout suivant certaines règles pour terminer avec un MPD (Modèle Physique de Données). Nous allons raccourcir
le processus et je vais fournir un modèle tout fait, que je vais tout de même vous expliquer...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 11/93
Tous ces beaux éléments seront nos futures tables. De plus, les attributs dans celles-ci se nomment des "champs".
Vous pouvez voir que tous les acteurs mentionnés se trouvent symbolisés dans ce schéma (classe, professeur, élève...). Vous
constaterez que ces acteurs ont un attribut nommé 'id', ceci correspond à son identifiant : c'est un champ de type entier qui
s'incrémentera pour chaque nouvelle entrée, c'est aussi grâce à ce champ que nous créons des liens entre nos acteurs.
Oui... Vous avez remarqué que j'avais colorié des tables en bleu.
Ces tables ont toutes un champ qui a une spécificité : un champ dont le nom se termine par '_k'.
D'abord, vous devez savoir que la flèche signifie 'a un', de ce fait, un élève 'a une' classe !
Bon, on te suit, mais pourquoi les autres tables ont deux champs comme ça ?
C'est simple, c'est parce que je vous ai dit qu'un professeur pouvait exercer plusieurs matières : dans ce cas, nous avons besoin
de ce qu'on appelle une table de jointure.
Ainsi, nous pouvons dire que tel professeur exerce telle ou telle matière et qu'une association prof-matière est assignée à une
classe !
La donnée que nous utiliserons pour lier des tables n'est autre que l'identifiant : id.
De plus - difficile de ne pas avoir vu ça - chaque champ à un type (entier, double, date, boolean...).
Nous avons tout ce dont nous avons besoin pour construire notre BDD !
Créer la BDD
Pour cette opération, rien de plus simple !
pgAdmin met à votre disposition un outil qui facilite la création de BDD et de tables (créer ses BDD et ses tables à la mano, avec
SQL, c'est un peu fastidieux...).
Pour créer une nouvelle base de données, il vous suffit de faire un clic droit sur "Base de données" :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 12/93
Renseignez le nom de la base de données et choisissez l'encodage UTF-8. Cet encodage correspond à un jeu de caractères
étendu qui autorise les caractères spéciaux !
Une fois ceci fait, vous devriez avoir quelque chose comme ça :
Vous pouvez voir votre nouvelle base de données ainsi que le script SQL permettant de créer cette base.
Il ne nous reste plus qu'à créer les tables avec le bon type de données...
Même procédure que pour la séquence, un clic droit sur le noeud "table" cette fois, comme ceci :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 13/93
Nous commencerons par la table "classe", vu que c'est l'une des tables qui n'a besoin d'aucun lien vers une autre table...
Comme dit plus haut, il vous suffit de faire un clic droit sur "Table"
Ensuite, PostgreSQL vous demande des informations sur votre future table :
son nom ;
le nom de ses champs ;
le type de ses champs ;
...
Ici, vous voyez le moment où vous devez renseigner le nom de votre table.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 14/93
Ensuite, vous ajouterez des champs (j'ai ajouté des préfixes à mes champs pour ne pas avoir trop d'ambiguïté dans mes requêtes
SQL) :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 15/93
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 16/93
Le champ "cls_id" est de type "serial" afin que celui-ci utilise une séquence. Nous lui ajouterons en plus une
contrainte de clé primaire.
Ce champ est un "character varying" de taille 64 : ce champ pourra donc contenir 64 caractères.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 17/93
Vous avez vu comment on crée une table avec PostgreSQL, mais je ne vais pas vous demander de faire ça pour chacune d'entre
elles.
Je ne suis pas vache à ce point... Nous devons voir comment on utilise les BDD avec Java, pas avec le SGBD...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 18/93
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 19/93
Je ne vais pas vous faire créer toutes les tables de cette manière... Le tuto est censé vous apprendre à utiliser les BDD avec
Java...
Voici donc un fichier contenant le script SQL de création des tables restantes ainsi que leurs contenus.
Sympa, le gars.
Il ne vous reste plus qu'à ouvrir le fichier avec PostgreSQL en allant dans l'éditeur de requêtes SQL :
Vous pouvez à présent ouvrir le fichier que je vous ai fourni en faisant "Fichier / Ouvrir" et choisir le fichier .sql
Maintenant, exécutez la requête en cliquant sur ce bouton (vous pouvez aussi appuyer sur F5) :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 20/93
Fermez l'éditeur de requête. Vous avez toute la base créée et, en plus, il y a des données.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 21/93
Se connecter à sa BDD
Nous avons pris le temps de modéliser et de créer notre base de données.
Il est grand temps de prendre le taureau par les cornes et de voir comment accéder à tout ceci dans un programme Java.
Inutile de préciser que savoir programmer en objets est plus que requis et que, mis à part ce point, tout sera pris à partir de ZérO.
En avant !
Faisons le point
Bon : vous avez utilisé pgAdmin jusqu'à maintenant. Le truc, c'est qu'il se passe des choses cachées, peu avouables voire
carrément obscènes entre pgAdmin et PostgreSQL.
Non, je plaisante... mais il se passe effectivement des choses entre ces deux-là !
Le fait est que vous ne devriez plus faire l'amalgame entre BDD et SGBD ; par contre, vous devez encore ignorer que le SGBD
effectue une connexion avec la BDD afin de pouvoir communiquer. Ceci pourrait se schématiser par un dialogue du genre :
Les ZérOs qui ont déjà installé une imprimante savent que leur machine à besoin d'un driver pour que la communication puisse
se faire entre les deux acteurs ! Ici, c'est la même chose !
pgAdmin utilise un driver pour se connecter à la base de données. Vu que les personnes qui ont développé les deux soft
travaillent main dans la main, pas de souci de communication mais qu'en sera-t-il avec Java ?
En fait, avec Java, vous allez avoir besoin de ces drivers, mais pas sous n'importe quelle forme !
Afin de pouvoir vous connecter à une base de données avec Java, il vous faut un fichier .jar qui correspond au fameux pilote.
Il existe donc un fichier .jar qui permet de se connecter à une base PostgreSQL !
MySQL ;
SQL Server ;
Oracle ;
...
Un bémol toutefois : vous pouvez aussi vous connecter à une BDD en utilisant les pilotes ODBC présents dans Windows, mais
ceci nécessite d'installer les pilotes dans Windows et de les paramétrer dans les sources de données ODBC pour, par la suite,
utiliser ces pilotes ODBC pour se connecter à la BDD dans un programme Java !
D'accord, on voit bien le principe ! Mais alors... où trouve-t-on ce pilote pour Java ?
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 22/93
Une simple recherche sur Google comblera vos attentes avec une recherche du genre :
pour MySQL...
Enfin bref, il est assez facile de trouver les pilotes JDBC convoités.
Sur la page de téléchargement des pilotes pour PostgreSQL, il y a la dernière version disponible ; j'ai pris la version JDBC4 :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 23/93
La version JDBC4 offre des nouveautés et une souplesse dans l'utilisation de JDBC, mais j'avoue, je ne les connais pas trop...
Vous trouverez un rapide aperçu par ici !
Bon ! Téléchargez le fichier .jar, pour ceux qui auraient la flemme de faire une recherche sur Google, c'est par ici ; et maintenant,
que faire de cette archive ?
Et comment on l'utilise ?
Pour l'utilisation, nous y arrivons à grand pas, mais une question se pose encore : où mettre l'archive ?
Vous avez deux solutions :
Le tout est de savoir si votre application est vouée à être exportée sur différents postes, auquel cas l'approche CLASSPATH est
encore la plus judicieuse (sinon, il faudra ajouter l'archive dans tous les JRE...) mais, nous, nous allons utiliser la deuxième
méthode afin de ne pas surcharger nos projets !
Je vous laisse donc mettre l'archive téléchargée dans le dossier sus-mentionné.
Connexion ! Es-tu là ?
La base de données est prête, les tables sont créées et remplies et nous avons le driver !
Il ne nous reste plus qu'à nous connecter, ENFIN !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 24/93
Eh, il faut ce qu'il faut ! Et encore, j'aurais pu vous faire réviser le SQL avant d'attaquer !
Je vous autorise à créer un nouveau projet dans Eclipse avec une classe contenant une méthode public static void
main(String[] args) .
Code : Java
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Enumeration;
import java.util.Properties;
try {
Class.forName("org.postgresql.Driver");
System.out.println("DRIVER OK ! ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Oui.
Nous allons détailler un peu tout ceci...
Dans un premier temps, nous avons créé une instance de l'objet Driver présent dans le fichier .jar que nous avons téléchargé
tout à l'heure.
Il est inutile de créer une véritable instance de ce type d'objet ; par-là, j'entends que faire ceci :
Code : Java
n'est pas nécessaire. Du coup, nous utilisons la réflexivité afin d'instancier cet objet.
À ce stade, il y a comme un pont entre votre programme Java et votre BDD, mais el trafique routier n'y est pas encore autorisé !
Il faut qu'une connexion soit effective afin que votre programme et la BDD puissent communiquer. Ceci se fait avec l'autre ligne
de code : Connection conn = DriverManager.getConnection(url, user, passwd); .
l'URL de connexion ;
le nom de l'utilisateur ;
le mot de passe utilisateur.
L'URL de quoi ?
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 25/93
De connexion. Elle est indispensable à Java pour se connecter à n'importe quelle BDD.
Cette URL se décompose comme suit :
En vert, vous pouvez voir le début de l'URL de connexion. elle commence TOUJOURS par " jdbc:". Dans notre cas, nous
utilisons PostgreSQL, la dénomination " postgresql:" suit le début de l'URL. Si vous utilisez une source de données ODBC, il
faudrait avoir "jdbc:odbc:".
En fait, ceci dépend du pilote JDBC : cela permet à Java de savoir quel pilote utiliser ! On parle de protocole utilisé.
En bleu, vous trouverez la localisation de la machine physique sur le réseau ; ici, nous sommes en local, nous utilisons donc
" //localhost:5432". Ah oui, le nom de la machine physique est suivi du numéro de port utilisé.
En orange, pour ceux qui ne l'auraient pas deviné, il s'agit du nom de notre base de données !
Les informations en bleu et en orange dépendent du pilote JDBC utilisé. Pour en savoir plus, consultez la
documentation de celui-ci !
L'URL, le nom d'utilisateur, le mot de passe et le driver permettent ensemble de créer le pont de connexion et le trafic routier sur
ce pont !
Donc, si vous exécutez ce code, vous aurez :
Vous n'êtes obligés de spécifier la totalité des informations pour l'URL... Mais il faudra au moins "jdbc:postgresql".
L'avantage avec les fichiers .jar comme drivers de connexion, c'est que vous n'êtes pas tenus d'initialiser le driver par
réflexivité ou autre. Tout se passe en Java ! Vu qu'il y a un rappel du protocole à utiliser dans l'URL de connexion, tout
est parfait et Java s'en sort tout seul !
Ne vous étonnez pas si vous ne voyez plus Class.forName("org.postgresql.Driver"); par la suite...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 26/93
Eh oui, une base de données n'est utile que si nous pouvons consulter, ajouter, modifier ou encore supprimer les données qu'elle
comprend.
Par contre, pour faire ceci, il était IMPÉRATIF de se connecter. Mais vu que c'est chose faite, nous allons voir comment fouiner
dans notre BDD.
Le couple Statement - ResultSet
Voici deux objets que vous utiliserez sûrement beaucoup !
En fait, ce sont ces deux objets qui permettent de récupérer des données de la BDD ou de travailler avec celles-ci...
Afin de vous faire comprendre tout ceci de façon simple, voici un exemple assez complet (mais pas trop quand même) affichant le
contenu de la table classe :
Code : Java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
try {
Class.forName("org.postgresql.Driver");
System.out.println("\n**********************************");
//On affiche le nom des colonnes
for(int i = 1; i <= resultMeta.getColumnCount(); i++)
System.out.print("\t" +
resultMeta.getColumnName(i).toUpperCase() + "\t *");
System.out.println("\n**********************************");
while(result.next()){
for(int i = 1; i <= resultMeta.getColumnCount(); i++)
System.out.print("\t" + result.getObject(i).toString() + "\t
|");
System.out.println("\n---------------------------------");
result.close();
state.close();
} catch (Exception e) {
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 27/93
e.printStackTrace();
}
}
}
Vous avez sûrement compris que j'ai simplement exécuté une requête SQL et récupéré les lignes trouvées ! Mais détaillons un
peu plus ce qu'il s'est passé.
Déjà, vous aurez pu remarquer que j'ai spécifié l'URL complète pour la connexion : sinon comment voulez-vous savoir
quelle BDD attaquer ?...
La connexion à la BDD mise à part, les choses se sont passées en quatre étapes distinctes :
Tout ça semble clair, mais tu ne pourrais pas nous en dire un peu plus sur ces objets ?
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 28/93
Dîtes-vous une chose : objet Statement => instruction SQL ! C'est cet objet qui exécute les requêtes SQL et qui retourne les
résultats.
Ensuite, lorsque vous entendez ResultSet, c'est que votre requête SQL a retourné un certain nombre de lignes à récupérer et à
afficher...
Comment ça fonctionne
Je vous ai fourni un morceau de code, il fonctionne, mais comment ça marche ?
Voici le moment où tout vous sera dévoilé.
Comme je vous le disais plus haut, l'objet Statement est l'objet qui vous permet de faire des requêtes SQL. Celles-ci peuvent être
de type :
CREATE ;
INSERT ;
UPDATE ;
SELECT ;
DELETE.
Vous n'êtes pas sans savoir que, selon le type de requête exécutée, celle-ci retourne un / des résultat(s), dans le cas d'un
SELECT, ou une validation / un message d'erreur dans les autres cas.
L'objet Statement vous est fourni par l'objet Connection grâce à l'instruction conn.createStatement(); .
Nous verrons, dans le chapitre suivant, un peu plus de choses concernant l'objet Statement.
Ce que j'ai fait ensuite, c'est demander à mon objet Statement d'exécuter une requête SQL de type SELECT. Vous la voyez, celle-
ci :
Code : SQL
Cette requête me retournant un résultat contenant beaucoup de lignes, elles-mêmes contenant plusieurs colonnes, nous avons
stocké ce résultat dans un objet ResultSet, objet permettant de faire diverses actions sur des résultats de requêtes SQL !
Après cette ligne de code : ResultSet result = state.executeQuery("SELECT * FROM classe"); , les
résultats sont stockés dans l'objet ResultSet et nous n'avons plus qu'à afficher les données.
Ici, j'ai utilisé un objet de type ResulSetMetaData afin de récupérer les "meta data" de ma requête. Comprenez ceci comme
"récupérer les informations globales de ma requête". Ici, nous avons utilisé cet objet afin de récupérer le nombre de colonnes
renvoyé par la requête SQL ainsi que leurs noms.
Cet objet "meta data" permettent de récupérer des informations très utiles comme :
Code : Java
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 29/93
System.out.println("\n**********************************");
//On affiche le nom des colonnes
for(int i = 1; i <= resultMeta.getColumnCount(); i++)
System.out.print("\t" + resultMeta.getColumnName(i).toUpperCase() +
"\t *");
System.out.println("\n**********************************");
Nous nous servons de la méthode nous donnant le nombre de colonnes dans le résultat afin de récupérer le nom de la colonne
grâce à son index !
ATTENTION : contrairement aux indices de tableaux, les indices de colonnes SQL commencent à1!
Ensuite, nous récupérons les données de notre requête en nous servant de l'indice des colonnes :
Code : Java
while(result.next()){
for(int i = 1; i <= resultMeta.getColumnCount(); i++)
System.out.print("\t" + result.getObject(i).toString() + "\t |");
System.out.println("\n---------------------------------");
}
Nous utilisons une première boucle afin que, tant que notre objet ResultSet nous retourne des lignes de résultats, nous
parcourions ensuite chaque ligne via notre boucle for .
La méthode next() permet de positionner l'objet sur la ligne suivante dans sa liste de résultat ! Au premier tour de
boucle, cette méthode positionne l'objet sur la première ligne. Si vous ne positionnez pas l'objet résultat et que vous
tentez de lire des données, une exception sera levée !
Je suis parti du postulat que ne connaissons pas le type de données de nos colonnes, mais vu que nous les connaissons, ce
code aurait tout aussi bien fonctionné :
Code : Java
while(result.next()){
System.out.print("\t" + result.getInt("cls_id") + "\t |");
System.out.print("\t" + result.getString("cls_nom") + "\t |");
System.out.println("\n---------------------------------");
}
On a le droit de faire ça ?
Tout à fait ! Nous connaissons le nom de nos colonnes retournées par la requête SQL, nous connaissons aussi leurs types, il
nous suffit donc d'invoquer la méthode adéquat de l'objet ResultSet en utilisant le nom de la colonne à récupérer !
Par contre, si vous essayez de récupérer le contenu de la colonne "cls_nom" avec la méthode
getInt("cls_nom") , vous aurez une zolie exception !
Il existe une méthode getXXX() par type primitif et quelques autres correspondant aux types SQL :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 30/93
getArray(int colummnIndex) ;
getAscii(int colummnIndex) ;
getBigDecimal(int colummnIndex) ;
getBinary(int colummnIndex) ;
getBlob(int colummnIndex) ;
getBoolean(int colummnIndex) ;
getBytes(int colummnIndex) ;
getCharacter(int colummnIndex) ;
getDate(int colummnIndex) ;
getDouble(int colummnIndex) ;
getFloat(int colummnIndex) ;
getInt(int colummnIndex) ;
getLong(int colummnIndex) ;
getObject(int colummnIndex) ;
getString(int colummnIndex) ;
Code : Java
result.close();
state.close();
Avant de voir plus en détail les possibilités qu'offrent ces objets, nous allons faire deux-trois requêtes SQL afin de nous habituer
à la façon dont tout ça fonctionne !
Entraînons-nous
Le but du jeu est de me coder les résultats que j'ai obtenus... Je vous laisse chercher dans quelle table...
Vous êtes prêts ? C'est parti !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 31/93
Cherchez bien...
Bon, vous avez trouvé ! Il n'y avait rien de compliqué ici, voici la correction, enfin, une suggestion de correction :
package com.sdz.exo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
try {
Class.forName("org.postgresql.Driver");
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 32/93
" colonnes dans cette table");
for(int i = 1; i <= resultMeta.getColumnCount(); i++)
System.out.println("\t *" + resultMeta.getColumnName(i));
while(result.next()){
System.out.print("\t" + result.getString("prof_nom") + "\t
|");
System.out.print("\t" + result.getString("prof_prenom") + "\t
|");
System.out.println("\n---------------------------------");
result.close();
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Hou... Ne vous faites pas exploser la cervelle tout de suite... On ne fait que commencer...
Voici une possible solution à ce résultat :
Secret (cliquez pour afficher)
Code : Java
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 33/93
package com.sdz.exo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
try {
Class.forName("org.postgresql.Driver");
while(result.next()){
if(!nom.equals(result.getString("prof_nom"))){
nom = result.getString("prof_nom");
System.out.println(nom + " " +
result.getString("prof_prenom") + " enseigne : ");
}
System.out.println("\t\t\t - " +
result.getString("mat_nom"));
}
result.close();
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 34/93
Code : Java
package com.sdz.exo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
try {
Class.forName("org.postgresql.Driver");
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 35/93
String nom = "";
String nomClass = "";
while(result.next()){
if(!nomClass.equals(result.getString("cls_nom"))){
nomClass = result.getString("cls_nom");
System.out.println("Classe de " + nomClass + " :");
}
if(!nom.equals(result.getString("prof_nom"))){
nom = result.getString("prof_nom");
System.out.println("\t * " + nom + " " +
result.getString("prof_prenom") + " enseigne : ");
}
System.out.println("\t\t\t - " +
result.getString("mat_nom"));
}
result.close();
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Voilà : maintenant que vous vous êtes bien entraînés, nous allons approfondir un peu tout ceci... Mais avant, le QCM des
familles.
C'est un chapitre riche mais pas trop compliqué...
Prenez le temps de voir comment le tout s'articule autour des Resultset et tutti quanti.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 36/93
Nous allons revenir sur les objets Statement et ResultSet en détaillant un peu le tout !
Statement
Vous avez vu comment obtenir un objet Statement ; par contre, ce que vous ignorez, c'est que je ne vous ai pas tout dit...
Je sais, je suis un vilain cysboy...
Vous savez déjà que, pour récupérer un objet Statement, vous devez le demander gentiment à un objet Connection, ceci en
invoquant la méthode createStatement() . Je ne vous apprends rien, là ! Du moins j'espère...
Par contre, ce que vous ne savez pas, c'est que vous pouvez spécifier des paramètres pour la création de l'objet Statement...
Ces paramètres permettent différentes actions lors du parcours des résultats via l'objet ResultSet.
TYPE_FORWARD_ONLY : le résultat n'est consultable qu'en avant. IMPOSSIBLE de revenir en arrière lors de la lecture
;
TYPE_SCROLL_SENSITIVE : le parcours peut se faire en avant ou en arrière, le curseur peut se positionner n'importe
où mais si des changements sont faits dans la base pendant la lecture, ces changements ne seront pas visibles ;
TYPE_SCROLL_INSENSITIVE : comme le précédent sauf que les changements sont directement visibles lors du
parcours des résultats.
CONCUR_READONLY : les données sont consultables en lecture seule. Pas de mise à jour des valeurs pour mettre la
base à jour ;
CONCUR_UPDATABLE : les données sont modifiables et, lors d'une modification, la base est mise à jour.
Par défaut, les ResultSet issus d'un Statement sont TYPE_FORWARD_ONLY pour le type de parcours et
CONCUR_READONLY pour les actions possibles.
Ces paramètres sont des variables statiques de la classe ResultSet, vous savez donc comment les utiliser...
Voici comment créer un Statement permettant à l'objet résultat de pouvoir être lu d'avant en arrière avec possibilité de
modification :
Code : Java
Statement state =
conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
Facile...
Vous avez appris à créer des Statement avec des paramètres, mais saviez-vous qu'il existe un autre type de Statement ?
Nous verrons comment utiliser les fonctionnalités des ResultSet juste après ce point...
Code : Java
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 37/93
nous avons :
Code : Java
Jusqu'ici, rien de particulier ! Cependant, une différence est déjà effective à ce stade : la requête SQL est pré-compilée !
Ceci a pour effet que celle-ci s'exécutera plus vite dans le moteur SQL de la BDD, c'est sûr puisqu'il n'aura pas à la compiler...
En fait, en règle générale, on utilise ce genre d'objet pour des requêtes ayant beaucoup de paramètres ou des requêtes pouvant
être exécutées plusieurs fois...
Non, bien sûr. Je vous ai dit dans le titre que nous allons préparer des requêtes !.
Il y a une différence de taille entre l'objet PreparedStatement et l'objet Statement : dans le premier, on peut utiliser des
paramètres à trous !
Quoi ?
Je me doutais que vous auriez du mal à comprendre... En fait, vous pouvez insérer un caractère spécial dans vos requêtes et
remplacer ce caractère grâce à des méthodes de l'objet PreparedStatement en spécifiant sa place et sa valeur (son type étant
défini par la méthode utilisée...).
Voici un exemple :
Code : Java
package com.sdz.prepare;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 38/93
prepare.close();
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
C'est simple : vous vous souvenez de la petite liste de méthodes de l'objet ResultSet pour récupérer des données ? À peu de
choses près, la même mais avec setXXX à la place de getXXX.
Tout comme son homologue sans trou, cet objet peut prendre les mêmes types de paramètres pour la lecture et pour la
modification des données lues :
Code : Java
Vous avez aussi une méthode retournant un objet ResultSetMetaData mais encore une méthode permettant de nettoyer les
changements de valeur des trous : prepare.clearParameters(); .
Si vous ajoutez cette méthode à la fin de ce que je vous ai fait tout à l'heure et que vous affichez à nouveau le contenu de notre
objet, vous aurez ceci :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 39/93
Bon, je pense que le moment est venu de voir l'objet ResultSet plus en détail...
ResultSet 2 : le retour
Nous allons voir comment se promener dans nos objets ResultSet, vu que nous avons vu comment permettre cela...
En fait, l'objet de résultat offre beaucoup de méthodes afin de pouvoir se promener dans les résultats.
Cela, si vous avez bien préparé l'objet Statement.
Code : Java
package com.sdz.resultset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//---------------------------------------------------------------
-----
//TOUT CECI, VOUS CONNAISSEZ
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/Ecole";
String user = "postgres";
String passwd = "postgres";
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 40/93
-----
//*
int i = 1;
System.out.println("\n\t---------------------------------------
");
System.out.println("\tLECTURE STANDARD.");
System.out.println("\t---------------------------------------");
while(res.next()){
System.out.println("\tNom : " + res.getString("prof_nom") + " \t
prénom : "+ res.getString("prof_prenom"));
//On regarde si nous sommes sur la dernière ligne du résultat
if(res.isLast())
System.out.println("\t\t* DERNIER RESULTAT !\n");
i++;
}
System.out.println("\t---------------------------------------");
System.out.println("\tLecture en sens contraire.");
System.out.println("\t---------------------------------------");
System.out.println("\t---------------------------------------");
System.out.println("\tAprès positionnement absolu du curseur à la
place N° " + i/2 + ".");
System.out.println("\t---------------------------------------");
//On positionne le curseur sur la ligne i/2, peu importe où on
est
res.absolute(i/2);
while(res.next())
System.out.println("\tNom : " + res.getString("prof_nom") + " \t
prénom : "+ res.getString("prof_prenom"));
System.out.println("\t---------------------------------------");
System.out.println("\tAprès positionnement relatif du curseur à
la place N° " + (i -(i-2)) + ".");
System.out.println("\t---------------------------------------");
//On met le curseur à la ligne actuelle moins i-2
//Si nous reculons donc de i-2 lignes
//Si nous n'avions pas mis de signe moins, nous aurions avancé
de i-2 lignes
res.relative(-(i-2));
while(res.next())
System.out.println("\tNom : " + res.getString("prof_nom") + " \t
prénom : "+ res.getString("prof_prenom"));
res.close();
state.close();
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 41/93
} catch (Exception e) {
e.printStackTrace();
}
}
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 42/93
Donc, lorsque vous voulez spécifiez la place du curseur sur la première ligne, vous utiliserez absolute(1); et ceci, peu
importe où vous vous trouvez !
J'espère que ce chapitre vous a permis d'y voir plus clair sur le fonctionnement global de tout ce mic-mac...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 43/93
En fait, durant la lecture, vous pouvez utilisez des méthodes qui ressemblent à celle que je vous ai déjà montrée lors du parcours
d'un résultat... Vous vous souvenez, les méthodes comme :
res.getAscii();
res.getBytes();
res.getInt();
res.getString();
...
Sauf qu'ici, vous remplacerez getXXX(); par updateXXX(); . Ces méthodes de mise à jour des données prennent deux
paramètres :
C'est simple :
Donc, changer la valeur d'un champ est très simple mais il faut, en plus des changements de valeurs, valider ces changements
pour qu'ils soient effectifs, et ceci se fait grâce à la méthode updateRow() . De la même façon, vous pouvez annuler des
changements avec la méthode cancelRowUpdates() .
Si vous avez à annuler des modifications, vous devrez le faire avant la méthode de validation, sinon, l'annulation sera
ignorée !
Code : Java
package com.sdz.resultset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 44/93
//---------------------------------------------------------------
-----
//TOUT CECI, VOUS CONNAISSEZ
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/Ecole";
String user = "postgres";
String passwd = "postgres";
//Et voilà !
System.out.println("*********************************");
System.out.println("APRES REMODIFICATION : ");
System.out.println("\tNOM : " + res.getString("prof_nom") + " -
PRENOM : " + res.getString("prof_prenom") + "\n");
res.close();
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 45/93
Donc, le temps d'un instant, les données ont été modifiées dans la base de données, nous avons donc réussi notre pari !
Ôte-nous d'un doute, une bête requête SQL n'aurait pas pu faire l'affaire ?
INSERT
UPDATE
DELETE
CREATE
Code : Java
package com.sdz.statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
try {
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/Ecole";
String user = "postgres";
String passwd = "postgres";
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 46/93
res = state.executeQuery(query);
res.first();
//On affiche à nouveau
System.out.println("\n\t\t APRES MAJ : ");
System.out.println("\t\t * NOM : " + res.getString("prof_nom") +
" - PRENOM : " + res.getString("prof_prenom"));
res = state.executeQuery(query);
res.first();
//on affiche une nouvelle fois
System.out.println("\n\t\t REMISE A ZERO : ");
System.out.println("\t\t * NOM : " + res.getString("prof_nom") +
" - PRENOM : " + res.getString("prof_prenom"));
prepare.close();
res.close();
state.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Ce qui me donne :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 47/93
Ici, nous avons utilisé un PreparedStatement, histoire de faire compliqué dès le premier coup...
Mais vous auriez pu tout aussi bien utiliser un Statement tout simple et invoquer la méthode executeUpdate(String
query) .
Vous savez quoi ? Pour les autres types de requêtes, il suffit d'invoquer la même méthode que pour la mise à jour... En fait, celle-ci
retourne un booléen qui permet de savoir si le traitement a réussi ou non.
Code : Java
Lorsque vous exécutez une requête de type INSERT, CREATE, UPDATE ou DELETE, ces requêtes modifient les données
présentes dans la base. Une fois exécutée, le moteur SQL valide directement ces modifications !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 48/93
Comme ceci, c'est vous qui avez le contrôle sur vos données !
On spécifie au moteur SQL de ne pas valider automatiquement. Ou plutôt de valider automatiquement les requêtes SQL avec une
méthode qui prend un booléen en paramètre, mais qui ne concernera pas l'objet Statement, mais l'objet Connection :
Code : Java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
} catch (Exception e) {
e.printStackTrace();
}
}
}
Par contre, lorsque vous voulez que vos requêtes soient prises en compte, il faut utiliser la méthode conn.commit(); .
En mode setAutoCommit(false); , si vous ne validez pas vos requêtes, elles ne seront pas prises en compte !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 49/93
Vous pouvez revenir à tout moment en mode validation automatique avec setAutoCommit(true);
Voici un exemple :
Code : Java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
state.executeUpdate(query);
result.close();
state.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Vous pouvez exécuter le code autant de fois que vous voulez, vous aurez toujours :
Vous voyez : malgré la requête de mise à jour, celle-ci est inopérante ! Oh oui ! Vous pouvez voir les modifications durant le temps
d'exécution du script, mais vu que vous n'avez pas validé les modifications, celles-ci sont annulées à la fin...
Pour que la mise à jour soit effective, il aurait fallu faire un conn.commit() avant la fin du script !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 50/93
Maintenant, je vous propose de voir comment uniformiser un peu tout ça... C'est vrai qu'établir tout le temps la connexion est un
peu fastidieux alors qu'une seule instance de celle-ci suffirait...
C'est ce que je vous propose de voir dans le chapitre qui suit.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 51/93
Après vous avoir fait découvrir tout ça, je me suis dis : montrer une approche un peu plus objet ne serait pas du luxe !
C'est vrai, se connecter sans arrêt à notre base de données commence à être fastidieux. Je vous propose donc d'y remédier avec
ce chapitre.
Pourquoi se connecter qu'une seule fois ?
Pourquoi tu veux absolument qu'on aie une seule instance de notre objet Connection ?
Parce que ça ne sert pas à grand-chose de réinitialiser la connexion à votre BDD. Rappelez-vous que la connexion sert à faire le
pont entre votre base et votre application. Pourquoi voulez-vous que votre application se connecte à chaque fois à votre BDD ?
Une fois la connexion effective, pourquoi vouloir la refaire ? Votre application et votre BDD peuvent discuter !
Code : Java
package com.sdz.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* URL de connection
*/
private String url = "jdbc:postgresql://localhost:5432/Ecole";
/**
* Nom du user
*/
private String user = "postgres";
/**
* Mot de passe du user
*/
private String passwd = "postgres";
/**
* Objet Connection
*/
private static Connection connect;
/**
* Constructeur privé
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 52/93
*/
private SdzConnection(){
try {
connect = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Méthode qui va nous retourner notre instance
* et la créer si elle n'existe pas...
* @return
*/
public static Connection getInstance(){
if(connect == null){
new SdzConnection();
}
return connect;
}
}
Nous avons ici une classe avec un constructeur privé (même si, ici, ce n'était pas nécessaire) : du coup, impossible d'avoir une
instance de cet objet et impossible d'accéder aux attributs puisqu'ils sont déclarés private !
Notre objet Connection est instancié dans le constructeur privé et la seule méthode accessible de l'extérieur de la classe est
getInstance() . C'est donc cette méthode qui aura pour rôle de créer la connexion lorsque celle-ci n'existe pas, et seulement
dans ce cas.
Code : Java
Ceci a pour but de voir quand la connexion est réellement créée. Ensuite, il ne nous manque plus qu'un code de test. Oh ! Ben ça
alors ! J'en ai un sous la main :
Code : Java
package com.sdz.connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
try {
//1
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 53/93
PreparedStatement prepare =
SdzConnection.getInstance().prepareStatement("SELECT * FROM classe
WHERE cls_nom = ?");
//2
Statement state = SdzConnection.getInstance().createStatement();
//3
SdzConnection.getInstance().setAutoCommit(false);
//Et 4 appels à la méthode getInstance()
DatabaseMetaData meta =
SdzConnection.getInstance().getMetaData();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Vous avez la preuve que l'instanciation ne se fait qu'une seule fois et donc, que notre connexion à la BDD est unique !
Bon, ça c'est compris, par contre, pourquoi tu disais que le constructeur n'était pas nécessaire ?
Tout simplement parce que nous aurions pu avoir cela à la place et ça aurait tout aussi bien fonctionné :
Code : Java
package com.sdz.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* URL de connection
*/
private static String url =
"jdbc:postgresql://localhost:5432/Ecole";
/**
* Nom du user
*/
private static String user = "postgres";
/**
* Mot de passe du user
*/
private static String passwd = "postgres";
/**
* Objet Connection
*/
private static Connection connect;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 54/93
/**
* Méthode qui va nous retourner notre instance
* et la créer si elle n'existe pas...
* @return
*/
public static Connection getInstance(){
if(connect == null){
try {
connect = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connect;
}
}
Par contre, vous devrez rajouter la déclaration static de vos paramètres de connexion...
Vous pouvez relancer le code de test, vous verrez qu'il fonctionne toujours !
J'ai mis un constructeur privé d'abord car vous deviez savoir que cela existait, mais c'était superflu dans notre cas...
D'accord, mais j'ai une application multi-threads, tu es sûr qu'il n'y aura pas de conflit ?
Hum ! Vous savez déjà répondre à cette question si vous avez lu le chapitre sur les threads du tuto Java !
Il vous suffit de synchroniser la méthode getInstance() et le tour est joué...
Mais, parce qu'il y a un mais... cette méthode ne règle le problème qu'avant que la connexion ne soit instanciée. Autrement dit,
une fois la connexion instanciée, la synchronisation ne sert plus à rien...
Le problème de multi-threading ne se pose pas vraiment pour une connexion à une BDD puisque ce singleton sert surtout de
passerelle entre votre BDD et votre application, mais il peut y avoir d'autres objets que des connexions SQL qui ne doivent être
instanciés qu'une fois et tous ne sont pas aussi laxistes concernant le multi-threading...
Voyons comment parfaire ce pattern avec un autre exemple qu'une connexion SQL...
Le singleton dans tous ces états
Alors... Nous allons travailler avec un autre exemple et vu que j'étais très inspiré, voici notre super singleton :
Code : Java
package com.sdz.connection;
/**
* Le singleton
*/
private static SdzSingleton single;
/**
* Variable d'instance
*/
private String name = "";
/**
* Constructeur privé
*/
private SdzSingleton(){
this.name = "Mon singleton";
System.out.println("\t\tCREATION DE L'INSTANCE ! ! !");
}
/**
* Méthode d'accès au singleton
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 55/93
* @return SdzSingleton
*/
public static SdzSingleton getInstance(){
if(single == null)
single = new SdzSingleton();
return single;
}
/**
* Accesseur
* @return
*/
public String getName(){
return this.name;
}
}
Oui, ce n'est pas que je manquais d'inspiration, c'est juste qu'avec une classe toute simple, on comprend mieux les choses...
Code : Java
package com.sdz.connection;
La politique du singleton est toujours bonne. Maintenant, je vais vous poser une question : quand croyez-vous que la création
d'une instance soit la plus judicieuse ?
C'est simple : ici, nous avons exécuté notre code et l'instance est créée lorsque qu'on la demande pour la première fois ! C'est le
principal problème que pose le singleton et le multi-threading : la première instance... Une fois celle-ci créée, il y a moins de
problème.
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 56/93
Oui, au chargement de la classe par la JVM et ceci se fait en instanciant notre singleton à sa déclaration dans la classe, soit,
comme ceci :
Code : Java
package com.sdz.connection;
/**
* Le singleton
*/
private static SdzSingleton single = new SdzSingleton();
/**
* Variable d'instance
*/
private String name = "";
/**
* Constructeur privé
*/
private SdzSingleton(){
this.name = "Mon singleton";
System.out.println("\n\t\tCREATION DE L'INSTANCE ! ! !");
}
/**
* Méthode d'accès au singleton
* @return SdzSingleton
*/
public static SdzSingleton getInstance(){
return single;
}
/**
* Accesseur
* @return
*/
public String getName(){
return this.name;
}
}
Avec ce code, c'est la machine virtuelle qui va se charger de charger l'instance du singleton, bien avant que n'importe quel
thread vienne taquiner la méthode getInstance() ...
Il y a une autre méthode permettant de faire ceci, mais elle ne fonctionne parfaitement que depuis le JDK 1.5...
On appelle cette méthode : "le verrouillage à double vérification".
Cette méthode consiste à utiliser le mot clé volatile combiné au mot clé synchronized.
Pour les ZérOs qui l'ignorent, déclarer une variable volatile permet de s'assurer un accès ordonné des threads à une variable
(plusieurs threads peuvent accéder à cette variable), Ceci marque le premier point de verrouillage.
Ensuite, la double vérification s'effectuera dans la méthode getInstance() , on synchronise UNIQUEMENT lorsque le
singleton n'est pas créé.
Code : Java
package com.sdz.connection;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 57/93
/**
* Le singleton
*/
private volatile static SdzSingleton single;
/**
* Variable d'instance
*/
private String name = "";
/**
* Constructeur privé
*/
private SdzSingleton(){
this.name = "Mon singleton";
System.out.println("\n\t\tCREATION DE L'INSTANCE ! ! !");
}
/**
* Méthode d'accès au singleton
* @return SdzSingleton
*/
public static SdzSingleton getInstance(){
if(single == null){
synchronized(SdzSingleton.class){
if(single == null)
single = new SdzSingleton();
}
}
return single;
}
/**
* Accesseur
* @return
*/
public String getName(){
return this.name;
}
}
Tiens, avec ce que nous venons de voir, ça me donne une idée de TP...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 58/93
TP : un testeur de requête
Bon, vous avez appris un tas de choses et il est grand temps de faire un peu de pratique !
Dans ce TP, je vais vous demander de réaliser un testeur de requête SQL... Vous ne voyez pas où je veux en venir ? Lisez donc la
suite...
Cahier des charges
Alors... Le but du jeu est de :
pouvoir avoir une IHM permettant la saisie d'une requête SQL dans un champ ;
lancer l'exécution de la requête grâce à un bouton ;
ce bouton devra être dans une barre d'outils ;
dans le cas où la requête renvoie 0 ou plusieurs résultats, afficher ceux-ci dans un JTable ;
le nom des colonnes devra être visible ;
en cas d'erreur, une pop-up (JOptionPane) contenant le message s'affichera ;
un petit message affichera le temps d'exécution de la requête ainsi que le nombre de lignes retournées en bas de fenêtre.
Pour les ZérOs n'ayant pas lu la partie événementielle du tuto Java, je vous autorise à faire une version en mode
console ; par contre, celle-ci n'aura pas de correction...
J'espère que vous vous êtes bien pris la tête sur ce TP. Bien sûr, pas dans le sens où il vous a torturé l'esprit durant des heures
jusqu'à vous rendre malades, mais plutôt dans le sens où celui-ci vous a permis de réfléchir et de découvrir des choses.
Bon, assez tergiversé, vous devez être impatient de voir ce que j'ai fait :
Code : Java
package com.sdz.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.swing.JOptionPane;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 59/93
/**
* URL de connection
*/
private static String url =
"jdbc:postgresql://localhost:5432/Ecole";
/**
* Nom du user
*/
private static String user = "postgres";
/**
* Mot de passe du user
*/
private static String passwd = "postgres";
/**
* Objet Connection
*/
private static Connection connect;
/**
* Méthode qui va retourner notre instance
* et la créer si elle n'existe pas...
* @return
*/
public static Connection getInstance(){
if(connect == null){
try {
connect = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "ERREUR DE
CONNEXION ! ", JOptionPane.ERROR_MESSAGE);
}
}
return connect;
}
}
Classe Fenetre.java
Code : Java
package com.sdz.tp;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import com.sdz.connection.SdzConnection;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 60/93
/**
* ToolBar pour le lancement des requêtes
*/
private JToolBar tool = new JToolBar();
/**
* Le bouton
*/
private JButton load = new JButton(new
ImageIcon("img/load.png"));
/**
* Le délimiteur
*/
private JSplitPane split;
/**
* Le conteneur de résultat
*/
private JPanel result = new JPanel();
/**
* Requête par défaut pour le démarrage
*/
private String requete = "SELECT * FROM classe";
/**
* Le composant dans lequel taper la requête
*/
private JTextArea text = new JTextArea(requete);
/**
* Constructeur
*/
public Fenetre(){
setSize(900, 600);
setTitle("TP JDBC");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
initToolbar();
initContent();
initTable(requete);
}
/**
* Initialise la toolbar
*/
private void initToolbar(){
load.setPreferredSize(new Dimension(30, 35));
load.setBorder(null);
load.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
initTable(text.getText());
}
});
tool.add(load);
getContentPane().add(tool, BorderLayout.NORTH);
}
/**
* Initialise le contenu de la fenêtre
*/
public void initContent(){
//Vous connaissez ça...
result.setLayout(new BorderLayout());
split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new
JScrollPane(text), result);
split.setDividerLocation(100);
getContentPane().add(split, BorderLayout.CENTER);
}
/**
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 61/93
try {
//On crée un statement
long start = System.currentTimeMillis();
Statement state = SdzConnection.getInstance()
.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
);
j++;
}
} catch (SQLException e) {
//Dans le cas d'une exception, on affiche une pop-up et on
efface le contenu
result.removeAll();
result.add(new JScrollPane(new JTable()), BorderLayout.CENTER);
result.revalidate();
JOptionPane.showMessageDialog(null, e.getMessage(), "ERREUR !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 62/93
", JOptionPane.ERROR_MESSAGE);
}
/**
* Point de départ du programme
* @param args
*/
public static void main(String[] args){
Fenetre fen = new Fenetre();
fen.setVisible(true);
}
Bien sûr, ce code n'est pas la perfection même, vous pouvez l'améliorer grandement !
Vous pouvez utiliser un autre composant que moi pour la saisie de la requête, un JTextPane par exemple : pour la coloration
syntaxique...
Vous pourriez avoir un menu qui vous permette de sauvegarder vos requêtes, un tableau interactif autorisant la modification des
données...
Bref, ce n'est pas les améliorations qui manquent.
Un TP assez riche et qui a dû vous demander quelques instants de réflexion...
Mais bon, rien d'insurmontable pour les ZérOs avertis que vous êtes.
Je vous propose maintenant de voir comment faire en sorte d'utiliser des objets Java correspondant à vos données dans votre
BDD !
J'imagine que vous aspirez à faire ceci depuis longtemps... Alors, rendez-vous au prochain chapitre !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 63/93
En fait, je suppose que vous avez dû essayer de faire en sorte que les données de votre base collent à vos objets, avec des
méthodes :
de récupération ;
de création ;
de mise à jour ;
de suppression.
Eleve ;
Matiere ;
Professeur ;
Classe.
Et, si nous suivons la logique des relations entre nos tables, nous avons des classes liées suivant le diagramme de classes
suivant :
Nous voyons les liens entre les objets avec ce diagramme : une classe est composée de plusieurs élèves et de plusieurs
professeurs, et un professeur peut exercer plusieurs matières !
Les tables de jointures de la base sont symbolisées par la composition dans nos objets.
Une fois ceci fait, nous devons coder ces objets avec les accesseurs et les mutateurs adéquats :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 64/93
On appelle ce genre d'objet des POJO, pour Plain Old Java Object !
Ce qui nous donne ces codes sources :
Classe Eleve.java
Code : Java
package com.sdz.bean;
/**
* ID
*/
private int id = 0;
/**
* Nom de l'élève
*/
private String nom = "";
/**
* Prénom de l'élève
*/
private String prenom = "";
//****************************************************
// CONSTRUCTEUR DE L'OBJET
//****************************************************
/**
* @param id
* @param nom
* @param prenom
*/
public Eleve(int id, String nom, String prenom) {
this.id = id;
this.nom = nom;
this.prenom = prenom;
}
public Eleve(){};
//****************************************************
// ACCESSEURS ET MUTATEURS
//****************************************************
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the nom
*/
public String getNom() {
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 65/93
return nom;
}
/**
* @param nom the nom to set
*/
public void setNom(String nom) {
this.nom = nom;
}
/**
* @return the prenom
*/
public String getPrenom() {
return prenom;
}
/**
* @param prenom the prenom to set
*/
public void setPrenom(String prenom) {
this.prenom = prenom;
}
}
Classe Matiere.java
Code : Java
package com.sdz.bean;
/**
* ID
*/
private int id = 0;
/**
* Nom du professeur
*/
private String nom = "";
//****************************************************
// CONSTRUCTEUR DE L'OBJET
//****************************************************
/**
* @param id
* @param nom
*/
public Matiere(int id, String nom) {
this.id = id;
this.nom = nom;
}
public Matiere(){}
//****************************************************
// ACCESSEURS ET MUTATEURS
//****************************************************
/**
* @return the id
*/
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 66/93
Classe Professeur.java
Code : Java
package com.sdz.bean;
import java.util.HashSet;
import java.util.Set;
/**
* ID
*/
private int id = 0;
/**
* Nom du professeur
*/
private String nom = "";
/**
* Prénom du professeur
*/
private String prenom = "";
/**
* Liste des matières dispensées
*/
private Set<Matiere> listMatiere = new HashSet<Matiere>();
//****************************************************
// CONSTRUCTEUR DE L'OBJET
//****************************************************
/**
* @param id
* @param nom
* @param prenom
*/
public Professeur(int id, String nom, String prenom) {
this.id = id;
this.nom = nom;
this.prenom = prenom;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 67/93
public Professeur(){}
//****************************************************
// ACCESSEURS ET MUTATEURS
//****************************************************
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the nom
*/
public String getNom() {
return nom;
}
/**
* @param nom the nom to set
*/
public void setNom(String nom) {
this.nom = nom;
}
/**
* @return the prenom
*/
public String getPrenom() {
return prenom;
}
/**
* @param prenom the prenom to set
*/
public void setPrenom(String prenom) {
this.prenom = prenom;
}
/**
* @return the listMatiere
*/
public Set<Matiere> getListMatiere() {
return listMatiere;
}
/**
* @param listMatiere the listMatiere to set
*/
public void setListMatiere(Set<Matiere> listMatiere) {
this.listMatiere = listMatiere;
}
/**
* Ajoute une matière à la liste des cours dispensés
* @param Matiere
*/
public void addMatiere(Matiere matiere){
this.listMatiere.add(matiere);
}
/**
* Retire une matière de la liste des cours dispensés
* @param Matiere
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 68/93
*/
public void removeMatiere(Matiere matiere){
this.listMatiere.remove(matiere);
}
Classe Classe.java
Code : Java
package com.sdz.bean;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* ID
*/
private int id = 0;
/**
* Nom du professeur
*/
private String nom = "";
/**
* Liste des professeurs
*/
private Set<Professeur> listProfesseur = new
HashSet<Professeur>();
/**
* Liste des élèves
*/
private Set<Eleve> listEleve = new HashSet<Eleve>();
//****************************************************
// CONSTRUCTEUR DE L'OBJET
//****************************************************
/**
* @param id
* @param nom
*/
public Classe(int id, String nom) {
this.id = id;
this.nom = nom;
}
public Classe(){}
//****************************************************
// ACCESSEURS ET MUTATEURS
//****************************************************
/**
* @return the id
*/
public int getId() {
return id;
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 69/93
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the nom
*/
public String getNom() {
return nom;
}
/**
* @param nom the nom to set
*/
public void setNom(String nom) {
this.nom = nom;
}
/**
* @return the listMatiere
*/
public Set<Professeur> getListProfesseur() {
return listProfesseur;
}
/**
* @param listMatiere the listMatiere to set
*/
public void setListProfesseur(Set<Professeur> listProfesseur) {
this.listProfesseur = listProfesseur;
}
/**
* @return the listMatiere
*/
public void addProfesseur(Professeur prof) {
if(!listProfesseur.contains(prof))
listProfesseur.add(prof);
}
/**
* @param listMatiere the listMatiere to set
*/
public void removeProfesseur(Professeur prof ) {
this.listProfesseur.remove(prof);
}
/**
* @return the listMatiere
*/
public Set<Eleve> getListEleve() {
return listEleve;
}
/**
* @param listMatiere the listMatiere to set
*/
public void setListEleve(Set<Eleve> listEleve) {
this.listEleve = listEleve;
}
/**
* Ajoute un élève à la classe
* @param eleve
*/
public void addEleve(Eleve eleve){
if(!this.listEleve.contains(eleve))
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 70/93
this.listEleve.add(eleve);
}
/**
* Retire un élève de la classe
* @param eleve
*/
public void removeEleve(Eleve eleve){
this.listEleve.remove(eleve);
}
/**
* Méthode equals
* @param cls
* @return
*/
public boolean equals(Classe cls){
return this.getId() == cls.getId();
}
Vous avez des données sérialisées dans une base de données et vous souhaitez y accéder et les manipuler avec des objets Java.
Cependant, votre entreprise est en pleine restructuration et vous ne savez pas si vos données vont :
Comment faire en sorte de ne pas avoir à modifier toutes les utilisations de nos objets ?
Comment faire un système adaptatif aux futures modifications de supports de données ?
Comment faire en sorte que les objets que nous allons utiliser restent tels qu'ils sont ?
Il pourrait y avoir beaucoup de problématiques de ce genre, mais le pattern DAO est là pour vous !
La définition d'un design pattern est toujours un peu pompeuse et mystifiée ; par contre, et ceux qui ont lu les chapitres
concernant les design patterns du tuto Java le confirmeront, ils apportent plus de souplesse et de robustesse à vos programmes
!
Le pattern DAO
Ce pattern permet de faire le lien entre la couche d'accès aux données et la couche métier d'une application. Il permet de mieux
maîtriser les changements susceptibles d'être opérés sur le système de stockage des données, donc, par extension, de préparer
une migration d'un système à un autre (BDD vers fichiers XML par exemple...).
Ceci se fait en séparant accès aux données (BDD) et objets métiers (POJO).
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 71/93
C'est normal, mais ne vous en faites pas, je vais tout vous expliquer...
Déjà, il y a une histoire de séparation des "couches métiers et couches d'accès aux données". Il s'agit ni plus ni moins de faire
en sorte qu'un type d'objet se charge de récupérer les données dans la base et qu'un autre type d'objet (souvent des POJO) soit
utilisé pour manipuler ces données. Schématiquement, ça nous donne :
Tout à fait.
Les objets que nous avons créés plus haut sont nos POJO, les objets utilisés par le programme pour manipuler les données de la
base.
Il ne nous reste plus qu'à créer les objets qui vont rechercher les données dans la base !
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 72/93
Comment va-t-on faire pour demander à nos objets DAO de récupérer tel type d'objet ou d'en sérialiser tel autre ? Avec
des cast ?
Vous aviez oublié que nous pouvions créer des classes génériques ?
Bon, je vous pardonne. Maintenant, voyons un peu les codes sources de ces objets :
Classe DAO.java
Code : Java
package com.sdz.dao;
import java.sql.Connection;
import com.sdz.connection.SdzConnection;
/**
* Constructeur
* @param conn
*/
public DAO(Connection conn){
this.connect = conn;
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 73/93
/**
* Méthode de création
* @param obj
* @return
*/
public abstract boolean create(T obj);
/**
* Méthode pour effacer
* @param obj
* @return
*/
public abstract boolean delete(T obj);
/**
* Méthode de mise à jour
* @param obj
* @return
*/
public abstract boolean update(T obj);
/**
* Méthode de recherche des informations
* @param id
* @return
*/
public abstract T find(int id);
}
Classe EleveDAO.java
Code : Java
package com.sdz.dao.implement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.sdz.bean.Eleve;
import com.sdz.dao.DAO;
try {
ResultSet result = this.connect
.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
).executeQuery(
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 74/93
);
if(result.first())
eleve = new Eleve(id,
result.getString("elv_nom"), result.getString("elv_prenom"));
} catch (SQLException e) {
e.printStackTrace();
}
return eleve;
}
Classe MatiereDAO.java
Code : Java
package com.sdz.dao.implement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.sdz.bean.Eleve;
import com.sdz.bean.Matiere;
import com.sdz.dao.DAO;
return false;
}
return false;
}
try {
ResultSet result = this.connect
.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
).executeQuery(
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 75/93
);
if(result.first())
matiere = new Matiere(id,
result.getString("mat_nom"));
} catch (SQLException e) {
e.printStackTrace();
}
return matiere;
}
return false;
}
Classe ProfesseurDAO.java
Code : Java
package com.sdz.dao.implement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.sdz.bean.Eleve;
import com.sdz.bean.Professeur;
import com.sdz.dao.DAO;
return false;
}
return false;
}
try {
ResultSet result = this.connect
.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 76/93
).executeQuery(
);
if(result.first()){
professeur = new Professeur(id,
result.getString("prof_nom"), result.getString("prof_prenom"));
result.beforeFirst();
MatiereDAO matDao = new
MatiereDAO(this.connect);
while(result.next())
professeur.addMatiere(matDao.find(result.getInt("mat_id")));
}
} catch (SQLException e) {
e.printStackTrace();
}
return professeur;
}
return false;
}
}
Classe ClasseDAO.java
Code : Java
package com.sdz.dao.implement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.sdz.bean.Classe;
import com.sdz.bean.Eleve;
import com.sdz.dao.DAO;
return false;
}
return false;
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 77/93
try {
ResultSet result = this.connect
.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
).executeQuery(
);
if(result.first()){
classe = new Classe(id,
result.getString("cls_nom"));
result = this.connect
.createStatement()
.executeQuery(
);
while(result.next())
classe.addProfesseur(profDao.find(result.getInt("prof_id")));
result = this.connect
.createStatement()
.executeQuery(
);
while(result.next())
classe.addEleve(eleveDao.find(result.getInt("elv_id")));
}
} catch (SQLException e) {
e.printStackTrace();
}
return classe;
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 78/93
return false;
}
Pour ne pas compliquer la tâche, je n'ai détaillé que la méthode de recherche des données, les autres sont des coquilles
vides...
Mais vous devriez être capables de faire ça tout seuls, normalement...
Premier test
Bon : nous avons réalisé une bonne partie de ce pattern, nous allons pouvoir faire notre premier test.
Une bonne partie ? Tu veux dire qu'il y a encore des choses à faire ?
Oui, nous verrons ça dans le prochain chapitre : pour le moment, testons ce que nous avons.
Par contre, je tiens à préciser que j'utilise toujours le singleton créé quelques chapitres plus haut !
Code : Java
import com.sdz.bean.Classe;
import com.sdz.bean.Eleve;
import com.sdz.bean.Matiere;
import com.sdz.bean.Professeur;
import com.sdz.connection.SdzConnection;
import com.sdz.dao.DAO;
import com.sdz.dao.implement.ClasseDAO;
import com.sdz.dao.implement.EleveDAO;
import com.sdz.dao.implement.ProfesseurDAO;
System.out.println("\n******************************************\n");
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 79/93
System.out.println("\n******************************************\n");
Qui me donne :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 80/93
Vous avez compris comment tout ça fonctionnait ? Ce n'est pas très dur en fin de compte. Je vous laisse quelques instants pour
lire, tester, relire, tester à nouveau...
Nous utilisons des objets spécifiques afin de rechercher dans la base des données qui nous servent à instancier des objets Java
habituels.
Ne prenez pas peur, le résultat sera à la hauteur de vos attentes... Même si ne connaissez rien à Java ni à XML (pour l'instant...).
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 81/93
Code : Java
class A{
public Object getData(int type){
Object obj;
//----------------------
if(type == 0)
obj = new B();
else if(type == 1)
obj = new C();
else
obj = new D();
//----------------------
obj.doSomething();
obj.doSomethingElse();
}
}
vous constatez qu'il y a une création d'objet et que ceci est conditionné par une variable. En fait, selon celle-ci, l'objet instancié
n'est pas le même. Nous allons donc extraire ce code (celui entre commentaires) pour le mettre dans une classe à part :
Code : Java
package com.sdz.transact;
Du coup, maintenant, lorsque nous voudrons instancier les objets de la fabrique, nous utiliserons celle-ci.
Comme ça :
Code : Java
B b = Factory.getData(0);
C c = Factory.getData(1);
//...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 82/93
Pourquoi faire tout ce ramdam ? Quel est le problème avec nos instances ?
C'est simple : en temps normal, nous travaillons avec des objets concrets, non soumis au changement. Cependant, dans le cas
qui nous intéresse, nos objets peuvent être amenés à changer et j'irais même plus loin : le type d'objet utilisé peut changer !
L'avantage d'utiliser une fabrique, c'est que les instances concrètes (utilisation du mot clé new) se fait à UN SEUL
ENDROIT !
Donc, si nous devons faire des changements, il ne se feront qu'à un seul endroit ! Si nous ajoutons un paramètre dans le
constructeur, par exemple...
Je savais que vous comprendriez vite. je vous propose maintenant de voir comment ce pattern est implémenté dans le pattern
DAO.
Fabriquer vos DAO
En fait, la factory dans le pattern DAO sert à construire nos instances d'objets d'accès aux données.
Du coup, vu que nous avons un super-type d'objet pour ces objets, nous savons quel type d'objet va retourner notre fabrique.
Code : Java
package com.sdz.dao;
import java.sql.Connection;
import com.sdz.connection.SdzConnection;
import com.sdz.dao.implement.ClasseDAO;
import com.sdz.dao.implement.EleveDAO;
import com.sdz.dao.implement.MatiereDAO;
import com.sdz.dao.implement.ProfesseurDAO;
/**
* Retourne un objet Classe interagissant avec la BDD
* @return
*/
public static DAO getClasseDAO(){
return new ClasseDAO(conn);
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 83/93
/**
* Retourne un objet Professeur interagissant avec la BDD
* @return
*/
public static DAO getProfesseurDAO(){
return new ProfesseurDAO(conn);
}
/**
* Retourne un objet Eleve interagissant avec la BDD
* @return
*/
public static DAO getEleveDAO(){
return new EleveDAO(conn);
}
/**
* Retourne un objet Matiere interagissant avec la BDD
* @return
*/
public static DAO getMatiereDAO(){
return new MatiereDAO(conn);
}
}
Code : Java
import com.sdz.bean.Classe;
import com.sdz.bean.Eleve;
import com.sdz.bean.Matiere;
import com.sdz.bean.Professeur;
import com.sdz.dao.DAO;
import com.sdz.dao.DAOFactory;
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("");
//----------------------------------------------
//On va rechercher des élèves
//----------------------------------------------
System.out.println("\n\t************************************************");
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 84/93
System.out.println("\n\t************************************************");
}
}
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 85/93
Vous pouvez être fiers de vous ! Vous venez d'implémenter le pattern DAO utilisant une fabrique.
C'était un peu effrayant, mais, au final ce n'est rien du tout...
Non, bien sûr... Le fait est que vous pouvez très bien avoir un type de DAO pour chaque type de gestion de données
(PostgreSQL, XML, MySQL...). Le vrai problème, c'est de savoir comment récupérer les DAO puisque nous avons délégué leurs
instanciations à une fabrique.
Vous allez voir, les choses les plus compliquées peuvent être aussi les plus simples.
D'une usine à une multinationale
Faisons le topo de ce que nous avons :
Le fait est que notre structure actuelle fonctionne pour notre système actuel... Ah ! Mais ! Qu'entends-je, qu'ouïe-je ?
Votre patron vient de trancher ! Vous allez utiliser PostgreSQL ET du XML !
Ah ! Je vous arrête !
Vous entendez ce que vous dites :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 86/93
Vous voulez mettre des conditions afin de savoir quel type d'instance retourner : ça ressemble grandement à une portion de code
pouvant être déclinée en fabrique !
Oui ! Notre fabrique actuelle nous permet de construire des objets accédant à des données se trouvant sur une base de données
PostgreSQL. Mais la problématique maintenant est de pouvoir aussi utiliser des données provenant de fichiers XML...
Je pense que vous êtes tous d'accord pour dire que ces deux usines ont un processus de fabrication très similaire.
Par là, j'entends que nous allons utiliser les mêmes méthodes sur les objets sortant de ces deux usines.
Voyez ça un peu comme une grande marque de pain qui aurait beaucoup de boulangeries dans tous les pays du monde ! Cette
firme a un savoir-faire évident, mais aussi des particularités : le pain ne se fait pas pareil dans tous les endroits du globe...
Pour vous, c'est comme si vous passiez commande directement au siège social qui, lui, va déléguer à l'usine qui permet de
répondre à vos attentes !
Schématiquement, ça donne ceci :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 87/93
Lorsque je vous dis ça, vous devez avoir une réaction quasi-immédiate : héritage - polymorphisme !
Ce qui va changer le plus, par rapport à notre ancienne fabrique, c'est que nous n'utiliserons plus de méthodes statiques, mais
des méthodes d'une instance concrète, et pour cause : impossible de créer une classe abstraite ou une interface avec des
méthodes statiques destinée à la redéfinition !
Donc, nous allons créer une classe abstraite pour nos futurs fabriques, celle-ci devra avoir les méthodes permettant de récupérer
les différents DAO ET une méthode permettant d'instancier la bonne fabrique !
Je vous ai préparé un diagramme de classe, vous verrez mieux comme ça :
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 88/93
Classe AbstractDAOFactory.java :
Code : Java
package com.sdz.dao;
/**
* Retourne un objet Classe interagissant avec la BDD
* @return
*/
public abstract DAO getClasseDAO();
/**
* Retourne un objet Professeur interagissant avec la BDD
* @return
*/
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 89/93
/**
* Méthode permettant de récupérer les Factory
* @param type
* @return AbstractDAOFactory
*/
public static AbstractDAOFactory getFactory(int type){
switch(type){
case DAO_FACTORY:
return new DAOFactory();
case XML_DAO_FACTORY:
return new XMLDAOFactory();
default:
return null;
}
}
}
Classe DAOFactory.java
Code : Java
package com.sdz.dao;
import java.sql.Connection;
import com.sdz.connection.SdzConnection;
import com.sdz.dao.implement.ClasseDAO;
import com.sdz.dao.implement.EleveDAO;
import com.sdz.dao.implement.MatiereDAO;
import com.sdz.dao.implement.ProfesseurDAO;
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 90/93
Classe XMLDAOFactory.java
Code : Java
package com.sdz.dao;
Vous devez y voir plus clair ; même si la classe XMLDAOFactory ne fait rien du tout, vous voyez le principe de base et c'est
l'important !
Nous avons maintenant une hiérarchie de classes capables de travailler ensemble.
Je reprends le dernier exemple que nous avions réalisé, avec un peu de modifications...
Code : Java
import com.sdz.bean.Classe;
import com.sdz.bean.Eleve;
import com.sdz.bean.Matiere;
import com.sdz.bean.Professeur;
import com.sdz.dao.AbstractDAOFactory;
import com.sdz.dao.DAO;
import com.sdz.dao.DAOFactory;
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("");
//----------------------------------------------
//On va rechercher des élèves
//----------------------------------------------
AbstractDAOFactory adf =
AbstractDAOFactory.getFactory(AbstractDAOFactory.DAO_FACTORY);
//On récupère un objet faisant le lien entre la base et nos objets
DAO<Eleve> eleveDao = adf.getEleveDAO();
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 91/93
System.out.println("\n\t************************************************");
System.out.println("\n\t************************************************");
}
}
Voilà, vous en savez plus sur ce pattern de conception et vous devriez être à même de coder le reste des méthodes (insertions,
mise à jour et suppression), il n'y a rien de compliqué : ce sont juste des requêtes SQL...
www.openclassrooms.com
Partie 1 : Java DataBase Connectivity 92/93
J'espère que ce dernier vous a plu et que vous avez appris tout plein de choses...
Nous nous retrouverons bientôt pour une autre API Java à découvrir ! Je ne vous dis pas encore laquelle...
www.openclassrooms.com