Charger des données depuis une base MySQL avec JDBC en 5 minutes
Date de publication : 13 février 2012.
Par
Thierry Leriche-Dessirier 
Ce mini article montre (par l'exemple) comment charger des données depuis une base MySQL, à l'aide de JDBC, en quelques minutes.
Commentez
I. Introduction
I-A. À propos
I-B. Avant de commencer
II. Découverte du projet d'exemple
II-A. Télécharger, installer et importer le projet d'exemple
II-B. Ce que fait déjà le projet
II-C. Avant de commencer
III. Action
III-A. Compléter le modèle
III-B. Créer un DAO vide
III-C. Ajouter le driver MySQL
III-D. Lecture des données
IV. Conclusions
V. Remerciements
VI. Annexes
VI-A. Liens
VI-B. Création de la base avec phpMyAdmin en image
VI-C. Les fichiers importants en entier
I. Introduction
Dans ce document, nous allons voir comment charger des données depuis une base MySQL à l'aide de JDBC, puis transformer ces données en objets de notre modèle.
 | La FAQ JDBC dit : "JDBC est une API (Application Programming Interface) Java disponible depuis la version 1.1 du JDK. Pour note, JDBC est un nom déposé et non un acronyme, même si en général on lui donne la définition suivante : Java DataBase Connectivity." |
I-A. À propos
Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexes.
I-B. Avant de commencer
Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :
- Java JDK 1.6.0_24-b07 ;
- Eclipse Indigo 3.7 JEE 64b ;
- Maven 3.0.3 ;
- MySQL 5.1.52 (avec EasyPHP 5.3.3.1).
II. Découverte du projet d'exemple
II-A. Télécharger, installer et importer le projet d'exemple
 | Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexes). |
II-B. Ce que fait déjà le projet
Le projet contient un DAO (Data Access Object) qui va lire une liste d'élèves à partir d'un fichier CSV. Ce DAO peut se résumer par les codes suivants.
| Interface EleveDao.java |
package com.thi.notes.dao;
import java.util.List;
import com.thi.notes.domain.Eleve;
public interface EleveDao {
List<Eleve> findEleves();
}
|
| Implémentation CsvEleveDao.java du DAO |
package com.thi.notes.dao;
...
import com.thi.notes.domain.Eleve;
import com.thi.notes.domain.Sexe;
public class CsvEleveDao implements EleveDao {
@Override
public List<Eleve> findEleves() {
...
}
}
|
Le DAO utilise donc les objets "Eleve" et "Sexe" dont les codes résumés sont les suivants.
| Eleve.java |
package com.thi.notes.domain;
import java.util.Date;
public class Eleve {
private String nom;
private String prenom;
private Integer annee;
private Sexe sexe;
private Date dateNaissance;
private String adresse;
public Eleve(String nom, String prenom, Integer annee, Sexe sexe, Date dateNaissance, String adresse) {
...
}
}
|
| Eleve.java |
package com.thi.notes.domain;
public enum Sexe {
HOMME("Garçon"),
FEMME("Fille");
private final String label;
Sexe(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
|
Enfin, la classe "DaoLauncher" permet de tester la lecture.
| DaoLauncher.java |
package com.thi.notes;
import java.util.List;
import com.thi.notes.dao.CsvEleveDao;
import com.thi.notes.dao.EleveDao;
import com.thi.notes.domain.Eleve;
public class DaoLauncher {
public static void main(String[] args) {
EleveDao eleveDao = new CsvEleveDao();
List<Eleve> eleves = eleveDao.findEleves();
System.out.println("Liste des eleves");
for (Eleve eleve : eleves) {
System.out.println(eleve);
}
}
}
|
II-C. Avant de commencer
Comme nous allons lire des données à partir de MySQL, encore faut-il avoir des tables et des valeurs dedans.
 | Si vous n'avez pas encore installé MySQL sur votre ordinateur, alors je vous conseille d'installer EasyPHP qui simplifie le processus d'installation et de configuration. En outre EasyPHP installe automatiquement le logiciel phpMyAdmin qui sera bien pratique pour manipuler la base. |
Commencez par créer la base "notes_eleves" à l'aide du script SQL suivant.
| create_database.sql |
CREATE DATABASE IF NOT EXISTS notes_eleves;
|
Puis la structure de la table "eleve", qui va contenir (sans surprise) la liste des élèves.
| create_table.sql |
CREATE TABLE IF NOT EXISTS `eleve` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`nom` varchar(100) DEFAULT NULL,
`prenom` varchar(100) DEFAULT NULL,
`classe` int(10) unsigned NOT NULL,
`date_naissance` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`adresse` varchar(250) DEFAULT NULL,
`sexe` enum('HOMME','FEMME') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
|
Puis insérez les données à l'aide du script suivant.
| insert_data.sql (script complet dans le fichier Zip) |
INSERT INTO `eleve` (`id`, `nom`, `prenom`, `classe`, `date_naissance`, `adresse`, `sexe`) VALUES
(1, 'Durand', 'Marie', 3, '1992-01-02 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(2, 'Alesi', 'Julie', 3, '1992-01-08 00:00:00', '72 av. Jean Dupont 75003 Paris', 'FEMME'),
(3, 'Martini', 'Carine', 3, '1992-01-17 00:00:00', '2 rue du Moulin 92230 Neullavy', 'FEMME'),
(4, 'Varola', 'Sophie', 3, '1992-01-21 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(5, 'Labiche', 'Lelou', 3, '1992-01-21 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(6, 'Dujardin', 'Anne', 3, '1992-02-03 00:00:00', '67 rue des Jardins 91800 Brunoy', 'FEMME'),
(7, 'Laventure', 'Martine', 3, '1992-02-15 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(8, 'Livradu', 'Alice', 3, '1992-02-18 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(9, 'Veronicci', 'Cerise', 3, '1992-03-01 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(10, 'Baladini', 'Mathilde', 3, '1992-03-12 00:00:00', '15 rue du Lac 75001 Paris', 'FEMME'),
(11, 'Michelet', 'Jean', 3, '1992-04-08 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(12, 'Dupond', 'Pierre', 3, '1992-04-09 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
...
(48, 'Valegin', 'Jean', 3, '1992-11-28 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(49, 'Eto', 'Gabin', 3, '1992-11-18 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(50, 'Fivolini', 'Kevin', 3, '1992-12-06 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(51, 'Laferme', 'Martin', 3, '1992-12-07 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(52, 'Dupuis', 'Vincent', 3, '1992-12-15 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME'),
(53, 'Lagrange', 'Alexandre', 3, '1992-12-28 00:00:00', '15 rue du Lac 75001 Paris', 'HOMME');
|
Enfin, créez un nouvel utilisateur nommé "dvp" et ayant le mot de passe "hello" à l'aide du script SQL suivant.
| Ajout d'un utilisateur (create_database.sql) |
CREATE USER 'dvp'@'%' IDENTIFIED BY 'hello';
GRANT SELECT , INSERT , UPDATE ON `notes\_eleves` . * TO 'dvp'@'%';
|
III. Action
III-A. Compléter le modèle
Durée estimée : 30 secondes.
La classe Eleve ne possède pas encore l'attribut "id", ce à quoi nous allons immédiatement remédier en complétant ce "bean".
| Eleve.java |
public class Eleve {
private Integer id;
private String nom;
private String prenom;
private Integer annee;
private Sexe sexe;
private Date dateNaissance;
private String adresse;
...
|
Pour faire bonne mesure, nous allons ajouter un constructeur prenant ce nouvel attribut en paramètre.
| Eleve.java |
public class Eleve {
private Integer id;
private String nom;
...
public Eleve(String nom, String prenom, Integer annee, Sexe sexe, Date dateNaissance, String adresse) {
...
}
public Eleve(Integer id, String nom, String prenom, Integer annee, Sexe sexe, Date dateNaissance, String adresse) {
this(nom, prenom, annee, sexe, dateNaissance, adresse);
this.id = id;
}
...
|
 | Ici, on ne se contente pas de modifier le constructeur déjà existant afin de conserver une compatibilité avec le code de lecture des fichiers CSV. |
III-B. Créer un DAO vide
Durée estimée : 30 secondes.
Sur le même modèle (sans jeu de mot) que CsvEleveDao, nous allons créer le DAO DbEleveDao (vide pour l'instant) pour charger les données depuis MySQL.
| Eleve.java |
package com.thi.notes.dao;
import java.util.ArrayList;
import java.util.List;
import com.thi.notes.domain.Eleve;
public class DbEleveDao implements EleveDao {
@Override
public List<Eleve> findEleves() {
List<Eleve> eleves = new ArrayList<Eleve>();
return eleves;
}
}
|
Plus tard, on utilisera ce nouveau DAO de la manière suivante.
| Utilisation |
EleveDao eleveDao2 = new DbEleveDao();
List<Eleve> eleves2 = eleveDao2.findEleves();
|
III-C. Ajouter le driver MySQL
Durée estimée : 30 secondes.
Nous devons aussi ajouter une dépendance vers le "driver" MySQL à notre projet. Pour cela, il faut ajouter le bloc suivant au fichier de configuration "pom.xml" de Maven.
| Dépendance au driver |
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
|
Il faut ensuite relancer une installation Maven à l'aide de la commande suivante.
| Maven en ligne de commande |
mvn clean install eclipse:eclipse
|
En fonction des éléments déjà présents sur l'ordinateur, la réponse de Maven devrait ressembler à la trace suivante.
| Maven en ligne de commande |
C:\dvp\notes>mvn clean install eclipse:eclipse
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Notes 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ notes ---
[INFO] Deleting C:\dvp\notes\target
[INFO]
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.704s
[INFO] Finished at: Wed Jan 25 20:36:01 CET 2012
[INFO] Final Memory: 13M/60M
[INFO] ------------------------------------------------------------------------
C:\dvp\notes>
|
Il faut aussi rafraîchir le workspace d'Eclipse (touche F5). On constate que plusieurs librairies sont apparues.

La dépendance dans Eclipse après le rafraîchissement
III-D. Lecture des données
Durée estimée : 3 minutes.
On entre dans le vif du sujet. Comme indiqué plus haut, nous allons donc lire la liste d'élèves, depuis la base de données MySQL.
On commence en créant quelques constantes, indiquant où trouver la base, son nom, le login de l'utilisateur créé plus haut ainsi que son mot de passe.
| Constantes dans le DAO |
public class DbEleveDao implements EleveDao {
private static String URL = "jdbc:mysql://localhost:3306/notes_eleves";
private static String LOGIN = "dvp";
private static String PASSWORD = "hello";
...
|
 | Dans un vrai projet, il faudra penser à mettre ces valeurs dans un fichier de configuration. |
On peut maintenant créer une connexion à la base.
| Connexion (sans la gestion des exceptions) |
package com.thi.notes.dao;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Connection;
...
public class DbEleveDao implements EleveDao {
private static String URL = "jdbc:mysql://localhost:3306/notes_eleves";
private static String LOGIN = "dvp";
private static String PASSWORD = "hello";
@Override
public List<Eleve> findEleves() {
List<Eleve> eleves = new ArrayList<Eleve>();
Connection con = DriverManager.getConnection(URL, LOGIN, PASSWORD);
...
|
 | Dans un vrai projet, il vaut mieux éviter de créer une connexion à chaque requête car c'est une opération longue et coûteuse. À la place on utilise un "gestionnaire de connexion" à qui on demande de nous fournir une connexion. Ce gestionnaire ouvre la (ou les) connexion(s) au lancement du programme pour qu'elle soit immédiatement disponible. Quand on n'a plus besoin de la connexion, on indique au gestionnaire qu'il peut la reprendre. Des serveurs comme Tomcat ou Websphere fournissent, sur le même principe, des "pools de connexion"... |
Puis on peut lancer une requête vers la base, sans oublier de relâcher les ressources à la fin.
| Lancement de la requête (sans la gestion des exceptions) |
...
private final static String QUERY_FIND_ELEVES = "SELECT * FROM eleve ";
@Override
public List<Eleve> findEleves() {
List<Eleve> eleves = new ArrayList<Eleve>();
Connection con = DriverManager.getConnection(URL, LOGIN, PASSWORD);
Statement stmt = con.createStatement();
ResultSet rset = stmt.executeQuery(QUERY_FIND_ELEVES);
rset.close();
stmt.close();
con.close();
...
|
Comme de nombreuses erreurs peuvent se produire, il faut gérer les exceptions.
| Gestion des exceptions |
@Override
public List<Eleve> findEleves() {
List<Eleve> eleves = new ArrayList<Eleve>();
Connection con = null;
Statement stmt = null;
try {
con = DriverManager.getConnection(URL, LOGIN, PASSWORD);
stmt = con.createStatement();
ResultSet rset = stmt.executeQuery(QUERY_FIND_ELEVES);
while (rset.next()) {
Eleve eleve = rsetToEleve(rset);
eleves.add(eleve);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
...
|
On peut maintenant transformer les données, qu'on a sous forme de "Resultset", en objets Eleve. Pour cela, il faut parcourir le "resultset" comme suit.
| Parcourt du Resultset |
...
con = DriverManager.getConnection(URL, LOGIN, PASSWORD);
stmt = con.createStatement();
rset = stmt.executeQuery(QUERY_FIND_ELEVES);
while ( rset.next() ) {
Integer id = rset.getInt("id");
String nom = rset.getString("nom");
String prenom = rset.getString("prenom");
Integer annee = rset.getInt("classe");
Date dateNaissance = rset.getDate("date_naissance");
String adresse = rset.getString("adresse");
String sexeStr = rset.getString("sexe");
Sexe sexe = Sexe.valueOf(sexeStr);
Eleve eleve = new Eleve(id, nom, prenom, annee, sexe, dateNaissance, adresse);
eleves.add(eleve);
}
...
|
Il ne reste plus qu'à réorganiser un peu le code (pour éviter d'avoir des méthodes trop grosses) et à factoriser les traitements. Le code final, avec ces changements, est disponible en annexes.
 | En annexes, je montre également comment lancer une requête avec des paramètres, à l'aide d'un PreparedStatement. |
IV. Conclusions
Ce petit document le prouve ; il est très simple de charger une liste depuis une base de données comme MySQL. On aurait pu réaliser les mêmes choses avec d'autres bases en ne changeant presque rien dans le code. Durant ce tutoriel, nous n'avons vu qu'un infime partie des fonctionnalités de JDBC mais l'essentiel, pour bien débuter, est là.
V. Remerciements
Je tiens à remercier, en tant qu'auteur de tutoriel rapide, toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien mais aussi à mes contacts et amis du web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.
Plus particulièrement j'adresse mes remerciements,
à
Gueritarish,
Mickael BARON (
keulkeul) et
Maxime Gault (
_Max_)
VI. Annexes
VI-A. Liens
VI-B. Création de la base avec phpMyAdmin en image

Création de la base et de l'utilisateur

Création de la table

Table créée

Insertion des données

Consultation des données
VI-C. Les fichiers importants en entier
| DbEleveDao.java |
package com.thi.notes.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.thi.notes.domain.Eleve;
import com.thi.notes.domain.Sexe;
public class DbEleveDao implements EleveDao {
private final static String URL = "jdbc:mysql://localhost:3306/notes_eleves";
private final static String LOGIN = "dvp";
private final static String PASSWORD = "hello";
private final static String QUERY_FIND_ELEVES = "SELECT * FROM eleve ";
private final static String QUERY_FIND_ELEVES_BY_CLASSE = "SELECT * FROM eleve WHERE classe = ? ";
private Connection getConnexion() throws SQLException {
final Connection con = DriverManager.getConnection(URL, LOGIN, PASSWORD);
return con;
}
@Override
public List<Eleve> findEleves() {
List<Eleve> eleves = new ArrayList<Eleve>();
Connection con = null;
Statement stmt = null;
try {
con = getConnexion();
stmt = con.createStatement();
final ResultSet rset = stmt.executeQuery(QUERY_FIND_ELEVES);
while (rset.next()) {
final Eleve eleve = rsetToEleve(rset);
eleves.add(eleve);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return eleves;
}
@Override
public List<Eleve> findElevesByClasse(Integer classe) {
List<Eleve> eleves = new ArrayList<Eleve>();
Connection con = null;
PreparedStatement stmt = null;
try {
con = getConnexion();
stmt = con.prepareStatement(QUERY_FIND_ELEVES_BY_CLASSE);
stmt.setInt(1, classe);
final ResultSet rset = stmt.executeQuery();
while (rset.next()) {
final Eleve eleve = rsetToEleve(rset);
eleves.add(eleve);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return eleves;
}
private Eleve rsetToEleve(final ResultSet rset) throws SQLException {
final Integer id = rset.getInt("id");
final String nom = rset.getString("nom");
final String prenom = rset.getString("prenom");
final Integer annee = rset.getInt("classe");
final Date dateNaissance = rset.getDate("date_naissance");
final String adresse = rset.getString("adresse");
final String sexeStr = rset.getString("sexe");
final Sexe sexe = Sexe.valueOf(sexeStr);
final Eleve eleve = new Eleve(id, nom, prenom, annee, sexe, dateNaissance, adresse);
return eleve;
}
}
|
J'attire votre attention sur le bloc suivant, correspondant à la recherche par critère à l'aide d'un PreparedStatement.
| DbEleveDao.java (extrait) |
public class DbEleveDao implements EleveDao {
...
private final static String QUERY_FIND_ELEVES_BY_CLASSE = "SELECT * FROM eleve WHERE classe = ? ";
@Override
public List<Eleve> findElevesByClasse(Integer classe) {
List<Eleve> eleves = new ArrayList<Eleve>();
Connection con = null;
PreparedStatement stmt = null;
try {
con = getConnexion();
stmt = con.prepareStatement(QUERY_FIND_ELEVES_BY_CLASSE);
stmt.setInt(1, classe);
final ResultSet rset = stmt.executeQuery();
...
|
| DaoLauncher.java |
package com.thi.notes;
import java.util.List;
import java.util.Map;
import com.thi.notes.dao.CsvEleveDao;
import com.thi.notes.dao.CsvNoteDao;
import com.thi.notes.dao.DbEleveDao;
import com.thi.notes.dao.EleveDao;
import com.thi.notes.dao.NoteDao;
import com.thi.notes.domain.Eleve;
public class DaoLauncher {
public static void main(String[] args) {
final EleveDao eleveDao = new CsvEleveDao();
final List<Eleve> eleves = eleveDao.findEleves();
System.out.println("Liste des eleves");
for (Eleve eleve : eleves) {
System.out.println(eleve);
}
final NoteDao noteDao = new CsvNoteDao();
final Map<String, Double> notes = noteDao.findNotesDernierExam();
System.out.println();
System.out.println("Notes des eleves");
for (String key : notes.keySet()) {
final Double note = notes.get(key);
System.out.println(key + " : " + note);
}
final EleveDao eleveDao2 = new DbEleveDao();
final List<Eleve> eleves2 = eleveDao2.findEleves();
System.out.println();
System.out.println("Liste des eleves en base");
for (Eleve eleve : eleves2) {
System.out.println(eleve);
}
final EleveDao eleveDao2 = new DbEleveDao();
final List<Eleve> eleves2 = eleveDao2.findEleves();
System.out.println();
System.out.println("Liste des eleves en base");
for (Eleve eleve : eleves2) {
System.out.println(eleve);
}
}
}
|


Les sources présentées sur cette page sont libres de droits
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ©
2011 Thierry Leriche-Dessirier. Aucune reproduction,
même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc. sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 €
de dommages et intérêts.
Cette page est déposée.