Java : gérer une base de données avec JDBC
Achref El Mouelhi
Docteur de l’université d’Aix-Marseille
Chercheur en programmation par contrainte (IA)
Ingénieur en génie logiciel
[Link]@[Link]
H & H: Research and Training 1 / 41
Plan
1 Introduction
2 Utilisation
3 Transactions
4 Restructuration du code
Classes connexion et dao
DataSource et fichier de propriétés
H & H: Research and Training 2 / 41
Introduction
JDBC
Pour se connecter à une base de données
Il nous faut un JDBC (qui varie selon le SGBD utilisé)
JDBC : Java DataBase Connectivity
I c
deE
SGBD : Système de Gestion de BasesU
H
L ées
donn
L MO
h r e fE
A c
c
H & H: Research and Training 3 / 41
Introduction
JDBC
Pour se connecter à une base de données
Il nous faut un JDBC (qui varie selon le SGBD utilisé)
JDBC : Java DataBase Connectivity
I c
deE
SGBD : Système de Gestion de BasesU
H
L ées
donn
L MO
h r e fE
c
JDBC ?
c A
Une API (interface d’application) créée par Sun Microsystems
Il permet d’accéder aux bases de données en utilisant un driver
JDBC
H & H: Research and Training 3 / 41
Introduction
JDBC
I c
JDBC 8.0.13
EL H
U
MO
Aller sur
L
[Link]
f E l’archive .zip
Télécharger et Dh
c r e
écompresser
c
A
H & H: Research and Training 4 / 41
Introduction
JDBC
Intégrer le driver dans votre projet
I c
E
Faire un clic droit sur le nom du projet et aller
H
Ldans New >
U
Folder
L MO
Renommer le répertoire
r e E puis valider
f lib
A h
cde l’archive décompressée dans lib
c
Copier le .jar
H & H: Research and Training 5 / 41
Introduction
JDBC
Ajouter JDBC au path du projet
Faire clic droit sur .jar qu’on a placé dans lib
Aller dans Build Path et choisir Add to Build Path
I c
ELH
U
L MO
f E
chre
c A
H & H: Research and Training 6 / 41
Introduction
JDBC
Ajouter JDBC au path du projet
Faire clic droit sur .jar qu’on a placé dans lib
Aller dans Build Path et choisir Add to Build Path
I c
Ou aussi
ELH
U
MO
Faire clic droit sur le projet dans Package Explorer et aller dans Properties
L
Properties
f E
hre
Dans Java Build Path, aller dans l’onglet Libraries
c
c A
Cliquer sur Add JARs
Indiquer le chemin du .jar qui se trouve dans le répertoire lib du projet
Appliquer
H & H: Research and Training 6 / 41
Introduction
JDBC
Ajouter JDBC au path du projet
Faire clic droit sur .jar qu’on a placé dans lib
Aller dans Build Path et choisir Add to Build Path
I c
Ou aussi
ELH
U
MO
Faire clic droit sur le projet dans Package Explorer et aller dans Properties
L
Properties
f E
hre
Dans Java Build Path, aller dans l’onglet Libraries
c
c A
Cliquer sur Add JARs
Indiquer le chemin du .jar qui se trouve dans le répertoire lib du projet
Appliquer
Vérifier qu’une section Referenced Libraries a apparu.
H & H: Research and Training 6 / 41
Utilisation
JDBC
Avant de commencer, voici le script SQL qui permet de créer la base de
données utilisée dans ce cours
CREATE DATABASE jdbc;
USE jdbc;
I c
E LH
CREATE TABLE personne(
num INT PRIMARY KEY AUTO_INCREMENT, OU
L M
nom VARCHAR(30),
prenom VARCHAR(30)
ref E
);
c h
c A
SHOW TABLES;
INSERT INTO personne (nom, prenom) VALUES ("Wick", "John"),
("Dalton", "Jack");
SELECT * FROM personne;
H & H: Research and Training 7 / 41
Utilisation
JDBC
Trois étapes I c
H
L cas)
Enotre
Charger le driver JDBC (pour MySQL dansU
la L
Établir la connexion avec E
MO
base de données
c h ref
c A
Créer et exécuter des requêtes SQL
H & H: Research and Training 8 / 41
Utilisation
JDBC
I c
EL H
Avant de commencer
O U
Tous les imports de ce chapitre sontM
fE L de [Link].*;
c h r e
c
A
H & H: Research and Training 9 / 41
Utilisation
JDBC
Chargement du driver 5
try {
[Link]("[Link]");
}
catch (ClassNotFoundException e) { I c
[Link]([Link]());
ELH
U
}
L MO
r8e f E
c h
Chargement du driver
try {
c A
[Link]("[Link]");
}
catch (ClassNotFoundException e) {
[Link]([Link]());
}
H & H: Research and Training 10 / 41
Utilisation
JDBC
Se connecter à la base de données
Il faut spécifier l’URL (de la forme
I
c
jdbc:mysql://hote:port/nombd) H
ELMySQL est installé
U
MO
hote : le nom de l’hôte sur lequel le serveur
L
(dans notre cas localhost ou [Link])
Eé par défaut par MySQL est 3306
futilis
r e
port : le port TCP/IP
h
nombd :A le c
nom de la base de données MySQL
c
Il faut aussi le nom d’utilisateur et son mot de passe (qui
permettent de se connecter à la base de données MySQL)
H & H: Research and Training 11 / 41
Utilisation
JDBC
Connexion à la base
String url = "jdbc:mysql://localhost:3306/jdbc";
String user = "root";
String password = "";
Connection connexion = null;
I c
try {
ELH
U
connexion = [Link](url, user, password);
} catch (SQLException e) {
[Link]();
L MO
f E
hre
}
finally {
c
c A
if (connexion != null)
try {
[Link]();
} catch (SQLException ignore) {
[Link]();
}
}
H & H: Research and Training 12 / 41
Utilisation
JDBC
I c
En cas de problème avec le chargement du driver, modifier l’URL
de connexion ainsi :
ELH
U
String url =
L MO
f E
"jdbc:mysql://localhost:3306/jdbc?useSSL=false&
serverTimezone=UTC";
chre
c A
H & H: Research and Training 13 / 41
Utilisation
JDBC
Préparation et exécution de la requête
// création de la requête (statement)
Statement statement = [Link]();
// Préparation de la requête
I c
EL H
String request = "SELECT * FROM Personne;";
O U
// Exécution de la requête M
ResultSet result = e fE L
c h r [Link](request);
c A
H & H: Research and Training 14 / 41
Utilisation
JDBC
Préparation et exécution de la requête
// création de la requête (statement)
Statement statement = [Link]();
// Préparation de la requête
I c
EL H
String request = "SELECT * FROM Personne;";
O U
// Exécution de la requête M
ResultSet result = e fE L
c h r [Link](request);
c
A
On utilise
executeQuery() pour les requêtes de lecture : select.
executeUpdate() pour les requêtes d’écriture : insert,
update, delete et create.
H & H: Research and Training 14 / 41
Utilisation
JDBC
Récupération des données
while ([Link]()) {
I c
// on indique chaque fois le nom de la colonne
ELH
et le type
U
int num = [Link]("num");
L MO
f E
String nom = [Link]("nom");
chre
String prenom = [Link]("prenom");
c A
[Link](num + " " + nom + " " +
prenom);
}
H & H: Research and Training 15 / 41
Utilisation
JDBC
On peut faire aussi
while ([Link]()) {
// on peut indiquer aussi l’index de la colonne
I c
et le type
ELH
U
int idPersonne = [Link](1);
L MO
E
String nom = [Link](2);
f
A c hre
String prenom = [Link](3);
c
pour tous les autres attributs
// pareil
[Link](nom + " " + prenom);
}
H & H: Research and Training 16 / 41
Utilisation
JDBC
Pour faire une insertion
Statement statement = [Link]();
String request = "INSERT INTO Personne (nom,prenom)
VALUES (’Wick’,’John’);";
I c
int nbr = [Link](request);
ELH
if (nbr ! = 0)
U
[Link]("insertion réussie");
L MO
f E
chre
c A
H & H: Research and Training 17 / 41
Utilisation
JDBC
Pour faire une insertion
Statement statement = [Link]();
String request = "INSERT INTO Personne (nom,prenom)
VALUES (’Wick’,’John’);";
I c
int nbr = [Link](request);
ELH
if (nbr ! = 0)
U
[Link]("insertion réussie");
L MO
f E
A c hre
c
La méthode
executeUpdate() retourne
0 en cas d’échec de la requête d’insertion, et 1 en cas de succès
le nombre de lignes respectivement mises à jour ou supprimées
H & H: Research and Training 17 / 41
Utilisation
JDBC
Pour récupérer la valeur de la clé primaire auto-générée
Statement statement = [Link]();
String request = "INSERT INTO Personne (nom,prenom) VALUES (’
Wick’,’John’);";
I c
primaire
ELH
// on demande le renvoi des valeurs attribuées à la clé
U
MO
[Link](request,Statement.RETURN_GENERATED_KEYS
);
f E L
h re attribuées à l’ensemble de tuples
// on parcourt les valeurs
c
c A = [Link]();
ajoutés
ResultSet
resultat
// on vérifie s’il contient au moins une valeur
if ([Link]()) {
[Link]("Le numéro généré pour cette personne :
" + [Link](1));
}
H & H: Research and Training 18 / 41
Utilisation
JDBC
Pour éviter les injections SQL, il faut utiliser les requêtes préparées
(pour la consultation, l’ajout, la suppression et la modification)
String request = "INSERT INTO Personne (nom,prenom)
VALUES (?,?);";
I c
PreparedStatement ps = [Link](
ELH
U
request,PreparedStatement.RETURN_GENERATED_KEYS);
[Link](1, "Wick");
L MO
[Link](2, "John");
f E
[Link]();
chre
c A
ResultSet resultat = [Link]();
if ([Link]())
[Link]("Le numéro généré pour cette
personne : " + [Link](1));
H & H: Research and Training 19 / 41
Utilisation
JDBC
Pour éviter les injections SQL, il faut utiliser les requêtes préparées
(pour la consultation, l’ajout, la suppression et la modification)
String request = "INSERT INTO Personne (nom,prenom)
VALUES (?,?);";
I c
PreparedStatement ps = [Link](
ELH
request,PreparedStatement.RETURN_GENERATED_KEYS);
U
[Link](1, "Wick");
L MO
[Link](2, "John");
f E
[Link]();
chre
c A
ResultSet resultat = [Link]();
if ([Link]())
[Link]("Le numéro généré pour cette
personne : " + [Link](1));
Attention à l’ordre des attributs
H & H: Research and Training 19 / 41
Transactions
JDBC
Les transactions
I c
ensemble de requête SQL
EL H
U
MOles requête SQL) soit rien
appliquant le principe soit tout (toutes
L
e
activées par défautravec
E
f MySQL
A h
c ées et gérées par le développeur
pouvant
c être désactiv
H & H: Research and Training 20 / 41
Transactions
JDBC
Pour désactiver l’auto-commit
[Link](false);
I c
ELH
U
Pour valider une transaction
L MO
f E
hre
[Link](false);
c
c A
Pour annuler une transaction
[Link](false);
H & H: Research and Training 21 / 41
Transactions
JDBC
Exemple avec les transactions
// désactiver l’auto-commit
[Link](false);
String request = "INSERT INTO Personne (nom,prenom) VALUES
I c
(?,?);";
ELH
PreparedStatement ps = [Link](request,
U
MO
PreparedStatement.RETURN_GENERATED_KEYS);
[Link](1, "Wick");
[Link](2, "John");
f E L
[Link]();
chre
c A
// valider l’insertion
[Link]();
ResultSet resultat = [Link]();
if ([Link]())
[Link]("Le numéro généré pour cette personne :
" + [Link](1));
H & H: Research and Training 22 / 41
Restructuration du code Classes connexion et dao
JDBC
Organisation du code
Il faut mettre toutes les données (url, nomUtilisateur,
I c
ELH
motDePasse...) relatives à notre connexion dans une classe
connexion U
L MO
E
Pour chaque table de la base de données, on crée une classe
f
hre
java ayant comme attributs les colonnes de cette table
c
c A
Il faut mettre tout le code correspondant à l’accès aux données
(de la base de données) dans des nouvelles classes et interfaces
(qui constitueront la couche DAO : Data Access Object)
H & H: Research and Training 23 / 41
Restructuration du code Classes connexion et dao
La classe MyConnection
package [Link];
public class MyConnection {
private static String url = "jdbc:mysql://localhost:3306/jdbc?useSSL=
false&serverTimezone=UTC";
private static String utilisateur = "root";
private static String motDePasse = "";
private static Connection connexion = null;
I c
private MyConnection() {
try {
ELH
U
MO
[Link]("[Link]");
motDePasse );
f E L
connexion = [Link]( url, utilisateur,
hre
} catch ( Exception e ) {
c
c A
[Link]();
}
}
public static Connection getConnection() {
if (connexion == null) {
new MyConnection();
}
return connexion;
}
H & H: Research and Training 24 / 41
Restructuration du code Classes connexion et dao
JDBC
La classe MyConnection (suite)
public static void stop() {
if (connexion != null) {
I c
try {
ELH
U
[Link]();
L MO
} catch (SQLException e) {
f E
[Link]();
chre
c A
}
}
}
}
H & H: Research and Training 25 / 41
Restructuration du code Classes connexion et dao
JDBC
La classe Personne
package [Link];
public class Personne{
I c
ELH
U
MO
private int num;
private String nom;
f E L
hre
private String prenom;
c
c A
// + getters + setters + constructeur sans param
ètre + constructeur avec 2 paramètres nom et
prénom + constructeur avec 3 paramètres
H & H: Research and Training 26 / 41
Restructuration du code Classes connexion et dao
JDBC
L’interface PersonneDao
package [Link];
import [Link];
I c
EL H
U
MO
import [Link];
fE L
h r e
public interface PersonneDao {
c save(Personne personne);
void
A
Personne
c remove(Personne personne);
Personne update(Personne personne);
Personne findById(int id);
List<Personne> getAll();
}
H & H: Research and Training 27 / 41
Restructuration du code Classes connexion et dao
La classe PersonneDaoImpl définie dans [Link]
public class PersonneDaoImpl implements PersonneDao {
@Override
public Personne save(Personne personne) {
Connection c = [Link]();
if (c != null) {
try {
PreparedStatement ps = [Link]("insert into
I c
RETURN_GENERATED_KEYS);
ELH
personne (nom,prenom) values (?,?); ", PreparedStatement.
[Link](1, [Link]());
U
[Link](2, [Link]());
L MO
[Link]();
f E
hre
ResultSet resultat = [Link]();
if ([Link]()) {
c
c A
[Link]([Link](1));
}
return personne;
} catch (SQLException e) {
[Link]();
}
}
return null;
}
H & H: Research and Training 28 / 41
Restructuration du code Classes connexion et dao
Exemple de la méthode save en utilisant les transactions
public Personne save(Personne personne) {
Connection c = [Link]();
if (c != null) {
try {
[Link](false);
PreparedStatement ps = [Link]("insert into
c
personne (nom,prenom) values (?,?); ", PreparedStatement.
I
RETURN_GENERATED_KEYS);
[Link](1, [Link]());
ELH
[Link](2, [Link]());
U
[Link]();
L MO
E
ResultSet resultat = [Link]();
f
hre
if ([Link]()) {
[Link]();
c
c A
[Link]([Link](1));
}
return personne;
} catch (SQLException e) {
[Link]();
}
}
return null;
}
H & H: Research and Training 29 / 41
Restructuration du code Classes connexion et dao
JDBC
La classe PersonneDaoImpl (suite)
@Override
public Personne findById(int id) {
Personne personne = null;
Connection c = [Link]();
if (c != null) {
I c
try {
ELH
PreparedStatement ps = [Link]("select * from
U
MO
personne where num = ?; ");
[Link](1, id);
E L
ResultSet r =[Link]();
f
hre
if ([Link]())
c
personne = new Personne([Link]("num"),[Link]("nom"),r.
c A
getString("prenom"));
} catch (SQLException e) {
[Link]();
}
}
return personne;
}
}
Il faut implémenter toutes les méthodes de l’interface PersonneDao
H & H: Research and Training 30 / 41
Restructuration du code Classes connexion et dao
Le Main pour tester toutes ces classes
package [Link];
import [Link];
import [Link];
public class Main {
I
c
public static void main(String args []) { L
E H
O U
L M =("Wick","John");
PersonneDaoImpl personneDaoImpl
Personne personne = newE
new PersonneDaoImpl();
ref = [Link](personne);
Personne
A c h
Personne insertedPersonne
c
if (insertedPersonne != null)
[Link]("personne numéro " + insertedPersonne.
getNum() + " a été insérée");
else
[Link]("problème d’insertion");
}
}
H & H: Research and Training 31 / 41
Restructuration du code Classes connexion et dao
JDBC
I
c
Remarque EL H
U
Oautres méthodes de
M
N’oublions pas d’implémenter les quatre
L
l’interface Dao
h r e fE
A c
c
H & H: Research and Training 32 / 41
Restructuration du code Classes connexion et dao
JDBC
Utilisation de la généricité avec les DAO
I
c
H
EL tables de la
Nous devons créer autant d’interfaces DAO que
U
bases de données
L MO
Pour éviter cela, on peut E une seule interface Dao avec un
ef utiliser
rtoutes
A h
type génériquecque les classes d’accès aux données
doivent
cl’implémenter.
H & H: Research and Training 33 / 41
Restructuration du code Classes connexion et dao
JDBC
L’interface Dao
package [Link];
I c
import [Link];
ELH
public interface Dao <T> { MO
U
f E L
c h re obj);
T save(T obj);
void remove(T
A obj);
Tcupdate(T
T findById(int id);
List<T> getAll();
}
H & H: Research and Training 34 / 41
Restructuration du code Classes connexion et dao
JDBC
La classe PersonneDaoImpl
I c
package [Link];
EL H
U
MO Dao<Personne>{
public class PersonneDaoImpl implements
L
...
h r e fE
A c
c
pour le reste
Rien ne change
H & H: Research and Training 35 / 41
Restructuration du code DataSource et fichier de propriétés
JDBC
Encore de la restructuration du code
I c
H
Mettre les données (url, nomUtilisateur, motDePasse...) relatives à
EL
U
notre connexion dans un fichier de propriétés que nous appelons
MO
[Link] (utilisé par certain framework comme Spring)
L
f E
A c hre
Créer une nouvelle classe (DataSourceFactory) qui va lire et
construire les différentes propriétés de la connexion
c
Utiliser DataSourceFactory dans MyConnection
H & H: Research and Training 36 / 41
Restructuration du code DataSource et fichier de propriétés
JDBC
Le fichier [Link] situé à la racine du projet (ayant la
I c
forme clé = valeur, le nom de la clé est à choisir par
l’utilisateur) EL H
U
L MO
url=jdbc:mysql://localhost:3306/jdbc?useSSL=false&
serverTimezone=UTCf E
username=root chre
c A
password=root
H & H: Research and Training 37 / 41
Restructuration du code DataSource et fichier de propriétés
Créons la classe MyDataSourceFactory dans [Link]
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class MyDataSourceFactory {
public static DataSource getMySQLDataSource() {
I c
Properties props = new Properties();
ELH
FileInputStream fis = null;
U
MysqlDataSource mysqlDataSource = null;
try {
L MO
f E
hre
fis = new FileInputStream("[Link]");
[Link](fis);
c
c A
mysqlDataSource = new MysqlDataSource();
[Link]([Link]("url"));
[Link]([Link]("username"));
[Link]([Link]("password"));
} catch (IOException e) {
[Link]();
}
return mysqlDataSource;
}
}
H & H: Research and Training 38 / 41
Restructuration du code DataSource et fichier de propriétés
JDBC
I
c
Remarque H
EpasL le driver
Dans MyDataSourceFactory, on ne pr O U
écise
[Link] car Lon M
f Elui même le driver.
utilise un objet de la classe
c h e
MysqlDataSource quircharge
c
A
H & H: Research and Training 39 / 41
Restructuration du code DataSource et fichier de propriétés
La classe MyConnection du package [Link]
import [Link];
import [Link];
import [Link];
public class MyConnection {
private static Connection connexion = null;
I c
private MyConnection() {
ELH
U
MO
DataSource dataSource = [Link]();
L
try {
f E
hre
connexion = [Link]();
c
} catch (SQLException e) {
c A
[Link]();
}
}
public static Connection getConnection() {
if (connexion == null) {
new MyConnection();
}
return connexion;
}
H & H: Research and Training 40 / 41
Restructuration du code DataSource et fichier de propriétés
Relançons le Main et vérifier que tout fonctionne correctement
package [Link];
import [Link];
import [Link];
public class Main {
I
c
public static void main(String args []) { L
E H
O U
L M =("Wick","John");
PersonneDaoImpl personneDaoImpl
Personne personne = newE
new PersonneDaoImpl();
ref = [Link](personne);
Personne
A c h
Personne insertedPersonne
c
if (insertedPersonne != null)
[Link]("personne numéro " + insertedPersonne.
getNum() + " a été insérée");
else
[Link]("problème d’insertion");
}
}
H & H: Research and Training 41 / 41