Vous êtes sur la page 1sur 31

Développement WEB

Spring Boot
Manal Mounir
manal.mounir@etu.uae.ac.ma
1

Année universitaire 2023/2024


Chapitre 2: JDBC

DÉVELOPPEMENT WEB – Spring boot


2023-2024

2
Introduction à JDBC
▪ JDBC pour Java DataBase Connectivity
▪ API Java adaptée à la connexion avec les bases de données Relationnelles et
Objet-Relationnelles
▪ L ’API Fournit un ensemble de classes et d’interfaces permettant l’utilisation
d’un ou plusieurs SGBD à partir d’un programme

JDBC

Database
Architecture de JDBC
ResultSet ResultSet ResultSet

API JDBC Statement PrepareStatement CallableStatement

Connection

Gestionnaire de pilotes JDBC DriverManager

JDBC-ODBC JDBC JDBC JDBC


bridge driver driver driver driver
Pilotes JDBC
for for
spécifiques à la
ODBC Oracle Sybase
base de données
driver
JDBC protocol

Oracle Sybase
SQL
Access
Server
Modèles de connexion en Java
Architecture 2-tiers Architecture 3-tiers

Couche applicative Couche applicative Couche middleware

Communication
directe avec le SGBD

SGBD (Système SGBD (Système


de Gestion de de Gestion de
Contient la logique Bases de Bases de
métier, l'interface Données) Données)
utilisateur et d'autres Divisée en deux
composants parties distinctes : la
spécifiques à logique métier et (Servlets, EJB,
l'application. l'interface utilisateur Services Web)
Mise en œuvre

0. Importer le package java.sql


1. Enregistrer le driver JDBC
2. Etablir la connexion à la base de données
3. Créer une zone de description de requête
4. Exécuter la requête
5. Traiter les données retournées
6. Fermer les différents espaces
Enregistrer le driver JDBC

• Méthode forName() de la classe Class :

Class.forName("com.mysql.jdbc.Driver");

Class.forName("oracle.jdbc.driver.OracleDriver");
URL de connexion :

• Accès à la base via un URL de la forme :


jdbc:<sous-protocole>://nom-srv:port/nom-bd

• qui spécifie :
• jdbc : l ’utilisation de JDBC
• <sous-protocole> : le driver ou le type de SGBD
• l ’identification de la base locale ou distante
• avec des paramètres de configuration éventuels
• nom utilisateur, mot de passe, ...
• Exemples :
String url = "jdbc:mysql://localhost:3306/dbeleve";
Connexion à la base

• Méthode getConnexion() de DriverManager


• 3 arguments :
• l ’URL de la base de données
• le nom de l ’utilisateur de la base
• son mot de passe

Connection connect = DriverManager.getConnection(url, user, password);

Établissement de la
Chargement des Drivers Appel à getConnection Essai des Pilotes
Connexion
Gestionnaire de pilotes
Enregistrement dans le Recherche du pilote capable de se
DriverManager connecter à la base de données essaie tous les pilotes Utilisation du pilote trouvé
enregistrés jusqu'à ce qu'il pour établir la connexion à
en trouve un qui peut gérer la base de données
la connexion

Connexion Résultante
La connexion est renvoyée
pour être utilisée dans le
programme
Création d ’un Statement
• L ’objet Statement possède les méthodes nécessaires pour réaliser les requêtes sur
la base associée à la connexion dont il dépend
• 3 types de Statement :

• Statement : requêtes statiques simples


Statement req1 = connexion.createStatement();

• PreparedStatement : requêtes dynamiques pré-compilées


(avec paramètres d ’entrée/sortie)
String str = "SELECT * FROM maTable WHERE colonne = ?";
PreparedStatement req2 = connexion.prepareStatement(str);

• CallableStatement : procédures stockées


String str = "{CALL maProcedure(?)}";
CallableStatement req3 = connexion.prepareCall(str);
Exécution d ’une requête
• 3 types d ’exécution :
• executeQuery() : pour les requêtes (SELECT) qui retournent un ResultSet (tuples résultants)

Statement st = connexion.createStatement();
ResultSet rs = st.executeQuery("SELECT nom, prenom FROM clients WHERE nom='itey' ORDER BY nom");

• executeUpdate() : pour les requêtes (INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE) qui
retournent un entier (nombre de tuples traités)
Statement st = connexion.createStatement();
int nb = st.executeUpdate("INSERT INTO dept(DEPT) VALUES(06)");

• execute() : pour requêtes inconnus. Renvoie true si la requête a donné lieu à la creation d ’un objet ResultSet
Statement st = connexion.createStatement();
boolean result = st.execute("SELECT nom, prenom FROM clients WHERE nom='itey' ORDER BY nom");

if (result) {
ResultSet rs = st.getResultSet();
// Traitement des résultats s'il y en a
} else {
int nb = st.getUpdateCount();
// Traitement du nombre de lignes affectées dans le cas d'une requête de mise à jour
}
Exécution d ’une requête
Code Java
• Le code SQL n ’est pas interprété par Java.
• C ’est le pilote associé à la connexion (et au JDBC
final par le moteur de la base de données) qui
interprète la requête SQL
• Si une requête ne peut s ’exécuter ou qu’une
erreur de syntaxe SQL a été détectée, Pilote JDBC (MySQL, Oracle, etc.)
l ’exception SQLException est levée

Interprétation et Exécution de la
Requête SQL

En cas d’erreur

Gestion d'Exceptions
(SQLException)
Exécution d ’une requête
Pilote JDBC
• Le driver JDBC effectue d ’abord un accès à la Premier Accès à la Base pour
base pour découvrir les types des colonnes Découvrir les Types de Données
impliquées dans la requête puis un 2ème Colonnes
pour l ’exécuter..

Types de Données des Colonnes


Découverts

Deuxième Accès à la Base pour


Exécuter la Requête SQL

Résultats de la Requête SQL avec


les Types de Données Adaptés
Exécution d ’une requête

Exécute la requête SQL

executeQuery()

ResultSet

Structure
Utilité
Permet l'accès et la
manipulation des données
extraites
Exécution d ’une requête
public class ExempleJDBC {

public static void main(String[] args) {


// Connexion à la base de données (assurez-vous d'avoir le pilote JDBC approprié)
String url = "jdbc:mysql://localhost:3306/product_database";
String utilisateur = "nom_utilisateur";
String motDePasse = "mot_de_passe"; Id nom prix
cursor
try (Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse)) {
1 Produit1 8000
// Création d'une instruction SQL next
Statement statement = connexion.createStatement();
cursor 2 Produit2 3000

// Exécution de la requête SQL et récupération du ResultSet 3 Produit3 5000


ResultSet resultSet = statement.executeQuery("SELECT * FROM Produits");

// Parcours des résultats avec une boucle while


while (resultSet.next()) {
// Accès aux valeurs des colonnes par index resultSet.getInt(1);
int id = resultSet.getInt(1);
String nom = resultSet.getString("nom");
double prix = resultSet.getDouble("prix"); resultSet.getString("nom");
// Traitement des données (exemple : affichage)
System.out.println("ID : " + id + ", Nom : " + nom + ", Prix : " + prix);
} resultSet.getDouble("prix");

} catch (Exception e) {
e.printStackTrace();
}
}
}
Types de données JDBC
SGBD
Requête SQL
Résultats sous forme de types
SELECT * FROM table spécifiques
(CHAR, DECIMAL INTEGER DATE …

Traduction des types


JDBC Driver JDBC Driver de données retournés
par le SGBD en types
Effectue la requete de données Java

Programme Java

- Récupération des données à l’aide des


SQLException méthodes : getInt, getString , getDouble,
getFloat …
Une mauvaise sélection de
méthode
Résultats sous forme de types de
données Java
(INT STRING DOUBLE FLOAT ,,,
Correspondance des types
Type SQL Type Java
CHAR, VARCHAR , LONGVARCHAR String
NUMERIC, DECIMAL java.math.BigDecimal
BINARY, VARBINARY, LONGVARBINARY byte[]
BIT boolean
INTEGER int
BIGINT long
REAL float
DOUBLE, FLOAT double
DATE java.sql.Date
TIME java.sql.Time
… …
Cas des valeurs nulles
Les méthodes getTYPE() de ResultSet convertissent une valeur NULL SQL en une valeur
acceptable par le type d ’objet demandé

En Java
Méthodes retournant un objet
Base de données getString(),

getObject(), null
NULL getDate()

Méthodes numériques
getByte()

getInt()
0
getDouble()

getBoolean() false
Fermer les différents espaces
try {
// Utilisation de ResultSet, Statement, et Connection
// ...

} catch (SQLException e) {
// Gestion des exceptions, si nécessaire
e.printStackTrace();

} finally {
// Fermeture propre des objets JDBC
try { Pour terminer proprement
if (resultSet != null) { un traitement, il faut
resultSet.close(); fermer les différents
} espaces ouverts. sinon le
if (statement != null) { garbage collector s ’en
statement.close();
occupera mais moins
}
if (connection != null) { efficace
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
Fermer les différents espaces

▪ La méthode getMetaData() permet d ’obtenir des informations sur


les types de données du ResultSet
▪ Elle renvoie des ResultSetMetaData
▪ On peut connaître entre autres :
✓ le nombre de colonne : getColumnCount()
✓ le nom d ’une colonne : getColumnName(int col)
✓ le type d ’une colonne : getColumnType(int col)
✓ le nom de la table : getTableName(int col)
public class ExempleMetadonneesJDBC {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/ma_base_de_donnees";
String utilisateur = "utilisateur";
String motDePasse = "mot_de_passe";

try (Connection connection = DriverManager.getConnection(url, utilisateur, motDePasse)) {


String sql = "SELECT id, nom, poste FROM employes";
try (PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery()) {
// Obtention des métadonnées
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
System.out.println("Nombre de colonnes : " + columnCount);
// Affichage des informations pour chaque colonne
for (int i = 1; i <= columnCount; i++) {
System.out.println("Nom de la colonne " + i + " : " + metaData.getColumnName(i));
System.out.println("Type de la colonne " + i + " : " + metaData.getColumnType(i));
System.out.println("Nom de la table de la colonne " + i + " : " + metaData.getTableName(i));
System.out.println("------------------------");
}
// Traitement du reste du ResultSet
while (resultSet.next()) {
// Récupération des données des colonnes (exemple : id, nom, poste)
int id = resultSet.getInt("id");
String nom = resultSet.getString("nom");
String poste = resultSet.getString("poste");

// Traitement des données...


System.out.println("ID : " + id + ", Nom : " + nom + ", Poste : " + poste);
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
PreparedStatement : Prévention des Attaques par Injection SQL

Requête SQL en concaténant des chaînes de caractères avec des données d'entrée utilisateur

String userInput = "'; DROP TABLE employes; --";


String sqlQuery = "SELECT * FROM employes WHERE nom = '" + userInput + "'";

SELECT * FROM employes WHERE nom = ''; DROP TABLE employes; --

code SQL
Requête SQL utilisant PreparedStatement

String userInput = "'; DROP TABLE employes; --";


String sqlQuery = "SELECT * FROM employes WHERE nom = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sqlQuery);
preparedStatement.setString(1, userInput);

SELECT * FROM employes WHERE nom = ''; DROP TABLE employes; --

valeur
PreparedStatement : Optimisation des Performances
public class ExempleOptimisationPerformances {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/ma_base_de_donnees";
String utilisateur = "utilisateur";
String motDePasse = "mot_de_passe";
try (Connection connection = DriverManager.getConnection(url, utilisateur, motDePasse)) {
// Requête SQL paramétrée
String sql = "SELECT * FROM employes WHERE poste = ?";
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
// Exécution répétée de la même requête avec des paramètres différents

// Première exécution pour les employés de type "Manager"


preparedStatement.setString(1, "Manager");
ResultSet resultSet1 = preparedStatement.executeQuery();
afficherResultats(resultSet1); ❖ plus rapide qu’un Statement classique
// Deuxième exécution pour les employés de type "Développeur"
❖ le SGBD analyse qu’une seule fois la
preparedStatement.setString(1, "Développeur"); requête (recherche d ’une stratégie
ResultSet resultSet2 = preparedStatement.executeQuery(); d ’exécution adéquate)
afficherResultats(resultSet2);
❖ pour de nombreuses exécutions d ’une
// ... Autres exécutions possibles avec différents paramètres même requête SQL avec des paramètres
variables
} catch (SQLException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void afficherResultats(ResultSet resultSet) throws SQLException {
while (resultSet.next()) {
// Traitement des données (exemple : affichage des détails de l'employé)
System.out.println("ID : " + resultSet.getInt("id") + ", Nom : " + resultSet.getString("nom") +
", Poste : " + resultSet.getString("poste"));
}}}
Validation de transaction : Commit
Par défaut, JDBC est configuré en mode auto-commit

Transaction 1
Instruction 1

Transaction 2 Commit 2
Instruction 2

...

Transaction n
Instruction n
Validation de transaction : Commit
Par défaut, JDBC est configuré en mode auto-commit

Transaction 1
Débiter le montant du
compte source

Transaction 2 Commit 2
Créditer le montant sur le
compte de destination

Base de données
l'opération de crédit échoue incohérente
public class ExempleModeAutoCommit {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/ma_base_de_donnees";
String utilisateur = "utilisateur";
String motDePasse = "mot_de_passe";

try (Connection connection = DriverManager.getConnection(url, utilisateur, motDePasse)) {


// Opération 1: Débit du compte source
debitCompte(connection, "compte_source", 100.00);

// Opération 2: Crédit du compte de destination


creditCompte(connection, "compte_destination", 100.00);
} catch (SQLException e) {
e.printStackTrace();
}
}
// Opération de débit d'un compte
private static void debitCompte(Connection connection, String compte, double montant) throws SQLException {
String sql = "UPDATE comptes SET solde = solde - ? WHERE numero = ?";
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setDouble(1, montant);
preparedStatement.setString(2, compte);
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
// Opération de crédit d'un compte
private static void creditCompte(Connection connection, String compte, double montant) throws SQLException {
String sql = "UPDATE comptes SET solde = solde + ? WHERE numero = ?";
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setDouble(1, montant);
preparedStatement.setString(2, compte);
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
Validation de transaction : Commit
Regroupement dans une seule transaction

l'opération de débit réussit l'opération de crédit réussit

Transaction
Débiter le montant du
Etat Exécution Exécution
compte source Operation 1 commit
initial Operation 2
Créditer le montant sur le
compte de destination
Rollback
Base de données
cohérente

Si l'une de ces opérations échoue,


la transaction est annulée
Rollback
public class ExempleTransaction {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/ma_base_de_donnees";
String utilisateur = "utilisateur";
String motDePasse = "mot_de_passe";

try (Connection connection = DriverManager.getConnection(url, utilisateur, motDePasse)) {


// Désactivation du mode automatique
connection.setAutoCommit(false);

try {
// Opération 1: Débit du compte source
debitCompte(connection, "compte_source", 100.00);

// Opération 2: Crédit du compte de destination


creditCompte(connection, "compte_destination", 100.00);

// Validation de la transaction
connection.commit();
} catch (SQLException e) {
// En cas d'erreur, rollback pour annuler les opérations précédentes
connection.rollback();
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}

}
Passage en mode manuel pour la gestion explicite des transactions
Exercice d’application:

Imaginez que vous développez une application de gestion de bibliothèque. Vous devez créer un système pour gérer les livres, les auteurs et
les emprunteurs. Utilisez JDBC pour interagir avec une base de données relationnelle.

▪ Livres : Cette table représente les informations sur les livres. La clé primaire est l'ISBN (International Standard Book Number), et la
table contient des informations telles que le titre, la date de publication, et le nombre d'exemplaires disponibles.
▪ Auteurs : Cette table contient des informations sur les auteurs. La clé primaire est l'AuteurID, et la table comprend le nom et le prénom
de l'auteur.
▪ Emprunteurs : Cette table représente les emprunteurs de livres. La clé primaire est l'EmprunteurID, et la table comprend des
informations telles que le nom, l'adresse, et le numéro de téléphone de l'emprunteur.
Exercice d’application:

▪ Dans la classe Bibliothèque, créez les méthodes suivantes pour gérer les différentes tables de la bibliothèque :
o creerTables : Cette méthode devra créer les tables nécessaires à la gestion des livres, des auteurs, des emprunteurs et des
emprunts. Assurez-vous d'inclure les clés primaires et étrangères appropriées.
➔ createAuteursTable(Connection connection)
➔ createEmprunteursTable(Connection connection)
➔ createEmpruntsTable(Connection connection)
o insererDonneesExemple : Insérez au moins un exemple de livre, d'auteur, d'emprunteur et d'emprunt dans votre base de
données. Assurez-vous que ces données exemplaires respectent les contraintes de clé étrangère.
o rechercherLivresParAuteur : Cette méthode devra accepter le nom d'un auteur en paramètre et retourner la liste des livres écrits
par cet auteur.
o rechercherLivresEmpruntes : Cette méthode devra retourner la liste des livres actuellement empruntés, avec les détails de
l'emprunteur.
o enregistrerEmprunt : Cette méthode devra accepter l'ISBN d'un livre et l'ID d'un emprunteur, puis enregistrer un nouvel emprunt
dans la base de données. Assurez-vous de mettre à jour le nombre d'exemplaires disponibles du livre.
Exercice d’application:

Consignes supplémentaires :
o Utilisez des requêtes paramétrées avec des PreparedStatement pour éviter les attaques par injection SQL.
o Gérez les transactions de manière appropriée, en particulier pour l'enregistrement d'un nouvel emprunt.
o Assurez-vous de gérer les exceptions JDBC correctement en les affichant à la console.

Note :
o Assurez-vous de télécharger le connecteur JDBC driver et de l'importer correctement dans votre projet
avant d'exécuter le programme.
o Pour MySQL, le pilote JDBC couramment utilisé est le connecteur MySQL JDBC. Vous devez télécharger le
connecteur MySQL JDBC depuis le site officiel de MySQL (https://dev.mysql.com/downloads/connector/j) et
l'ajouter à votre projet Java.

Vous aimerez peut-être aussi