JDBC
Accès à une base de données
Notions théoriques
Qu'est-ce que JDBC ?
JDBC (Java Database Connectivity) est l'API standard Java pour se connecter à une base de données relationnelle. Elle permet d'exécuter des requêtes SQL depuis un programme Java, quel que soit le système de base de données (MySQL, PostgreSQL, SQLite...).
Pour utiliser MySQL, il faut ajouter le driver MySQL Connector/J en dépendance Maven :
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
Se connecter avec DriverManager.getConnection()
import java.sql.Connection;
import java.sql.DriverManager;
String url = "jdbc:mysql://localhost:3306/ma_base";
String user = "root";
String password = "monMotDePasse";
Connection conn = DriverManager.getConnection(url, user, password);
L'URL de connexion JDBC suit le format : jdbc:mysql://hôte:port/nomBase
PreparedStatement — Les requêtes paramétrées
Construire une requête SQL par concaténation de String est dangereux :
// DANGEREUX - injection SQL possible !
String sql = "SELECT * FROM eleves WHERE nom = '" + nomSaisi + "'";
Si nomSaisi contient ' OR '1'='1, la requête retournera tous les enregistrements. Utilise toujours PreparedStatement avec des ? comme paramètres :
import java.sql.PreparedStatement;
import java.sql.ResultSet;
String sql = "SELECT * FROM eleves WHERE nom = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, nomSaisi); // paramètre 1 = premier ?
ResultSet rs = stmt.executeQuery();
Lire les résultats avec ResultSet
ResultSet est un curseur qui parcourt les lignes retournées par une requête SELECT :
while (rs.next()) {
int id = rs.getInt("id");
String nom = rs.getString("nom");
double note = rs.getDouble("note");
System.out.println(id + " - " + nom + " : " + note);
}
rs.next()passe à la ligne suivante et retournefalsequand il n'y en a plusrs.getString("colonne"),rs.getInt("colonne"),rs.getDouble("colonne"): lecture par nom de colonne
Insérer et mettre à jour avec executeUpdate()
Pour les requêtes INSERT, UPDATE, DELETE :
String sql = "INSERT INTO eleves (nom, note) VALUES (?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, "Alice");
stmt.setDouble(2, 15.5);
int nbLignesAffectees = stmt.executeUpdate();
System.out.println(nbLignesAffectees + " ligne(s) insérée(s).");
Fermer les ressources avec try-with-resources
Les connexions, statements et result sets sont des ressources à fermer :
String url = "jdbc:mysql://localhost:3306/ma_base";
try (Connection conn = DriverManager.getConnection(url, "root", "pass");
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM eleves");
ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getString("nom"));
}
} catch (Exception e) {
System.out.println("Erreur SQL : " + e.getMessage());
}
// conn, stmt et rs sont fermés automatiquement
Exemple pratique
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class GestionEleves {
private static final String URL = "jdbc:mysql://localhost:3306/lycee";
private static final String USER = "root";
private static final String PASS = System.getenv("DB_PASSWORD");
public static void listerEleves() {
String sql = "SELECT id, nom, note FROM eleves ORDER BY note DESC";
try (Connection conn = DriverManager.getConnection(URL, USER, PASS);
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
System.out.println("=== Liste des élèves ===");
while (rs.next()) {
System.out.printf("%-20s %.1f%n",
rs.getString("nom"),
rs.getDouble("note"));
}
} catch (Exception e) {
System.out.println("Erreur : " + e.getMessage());
}
}
public static void ajouterEleve(String nom, double note) {
String sql = "INSERT INTO eleves (nom, note) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(URL, USER, PASS);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, nom);
stmt.setDouble(2, note);
int nb = stmt.executeUpdate();
System.out.println(nb + " élève(s) ajouté(s).");
} catch (Exception e) {
System.out.println("Erreur insertion : " + e.getMessage());
}
}
public static void main(String[] args) {
ajouterEleve("Alice", 15.5);
listerEleves();
}
}
Utilise des constantes private static final pour l'URL, le user et le mot de passe (ou mieux : lis-les depuis des variables d'environnement comme dans l'exemple). Cela évite de répéter ces valeurs dans chaque méthode.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez créer une classe DaoEleve (DAO = Data Access Object) qui centralise les accès à la table eleves.
La table SQL à créer :
CREATE TABLE eleves (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
note DOUBLE
);
Étape 1 — Méthode de connexion
Crée une méthode privée qui retourne une Connection en lisant les paramètres depuis des variables d'environnement.
Centralise la création de connexion dans une seule méthode privée. Si vous changez de base de données ou de mot de passe, vous n'avez qu'un seul endroit à modifier. Le pattern DAO (Data Access Object) applique ce principe à toutes les opérations sur une table.
Étape 2 — Méthode de lecture (SELECT)
Crée une méthode qui retourne tous les élèves depuis la base de données.
try-with-resources avec plusieurs ressources les ferme dans l'ordre inverse de déclaration : d'abord rs, puis stmt, puis conn. C'est l'ordre correct car une ressource peut dépendre de la précédente.
Étape 3 — Méthode d'insertion (INSERT)
Crée une méthode qui insère un nouvel élève en utilisant un PreparedStatement.
Toujours utiliser setString pour les String, setInt pour les int, setDouble pour les double, etc. N'utilise pas setString pour tout : JDBC doit connaître le type pour construire correctement la requête paramétrée et protéger contre les injections.