JDBC (Java DataBase Connectivity) est l’API Java standard permettant à une application de se connecter à une base de données relationnelle, d’exécuter des requêtes SQL et de récupérer les résultats.
Il permet de travailler avec différents SGBD en conservant la même logique générale côté Java. Le développeur ou la développeuse manipule des objets Java standards, tandis que le pilote JDBC assure la communication avec la base de données.
JDBC a 3 rôles principaux :
Avec JDBC, on dispose donc d’une solution simple et normalisée pour accéder à une base de données depuis Java, à condition d’ajouter le pilote correspondant au SGBD utilisé.
Dans ce cours, nous utiliserons PostgreSQL.
Pour communiquer avec PostgreSQL depuis Java, il faut ajouter le pilote JDBC PostgreSQL au projet.
C’est la méthode recommandée.
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.7.5</version> </dependency>
Vous pouvez télécharger le fichier .jar du pilote PostgreSQL puis l’ajouter au projet Eclipse ou IntelliJ.
.jar
Le nom du fichier ressemble généralement à ceci :
postgresql-42.7.5.jar
JDBC s’insère entre votre application Java et le système de gestion de base de données.
Application Java ↓ JDBC API ↓ Pilote PostgreSQL ↓ Base PostgreSQL
L’idée est simple :
java.sql
Tous les objets et méthodes liés à JDBC se trouvent principalement dans le package java.sql.
Les principales interfaces et classes utilisées sont :
SELECT
Exemple d’imports fréquents :
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;
Quel que soit le SGBD, les étapes sont toujours quasiment les mêmes :
Historiquement, on chargeait explicitement le pilote avec Class.forName(...).
Class.forName(...)
Class.forName("org.postgresql.Driver");
Avec les versions modernes de Java et du pilote PostgreSQL, ce chargement explicite n’est souvent plus obligatoire, car le pilote est détecté automatiquement s’il est présent dans le projet.
Mais pédagogiquement, il est utile de le montrer pour bien comprendre ce qui se passe.
try { Class.forName("org.postgresql.Driver"); System.out.println("Pilote PostgreSQL chargé avec succès."); } catch (ClassNotFoundException e) { System.out.println("Pilote PostgreSQL introuvable."); e.printStackTrace(); }
Voici les paramètres habituels pour une connexion JDBC avec PostgreSQL :
private static final String PILOTE = "org.postgresql.Driver"; private static final String URL = "jdbc:postgresql://localhost:5432/pratique"; private static final String UTILISATEUR = "postgres"; private static final String MOT_DE_PASSE = "postgres";
jdbc:postgresql://localhost:5432/pratique
jdbc
postgresql
localhost
5432
pratique
Attention : le port PostgreSQL par défaut est généralement 5432.
Une fois le pilote disponible, on ouvre la connexion grâce à DriverManager.getConnection(...).
DriverManager.getConnection(...)
Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse);
import java.sql.Connection; import java.sql.DriverManager; public class GestionConnexionPostgres { public static void main(String[] args) { try { Class.forName("org.postgresql.Driver"); String url = "jdbc:postgresql://localhost:5432/pratique"; String utilisateur = "postgres"; String motDePasse = "postgres"; Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse); System.out.println("Connexion PostgreSQL réussie !"); connexion.close(); } catch (Exception e) { System.out.println("La connexion a échoué."); e.printStackTrace(); } } }
Lorsque la connexion est établie, on peut envoyer des requêtes SQL à PostgreSQL.
Il existe trois grandes manières de travailler :
Statement
PreparedStatement
CallableStatement
Statement instruction = connexion.createStatement();
ResultSet resultat = instruction.executeQuery( "SELECT nom, prenom, age FROM apprenants" );
executeQuery()
executeUpdate()
INSERT
UPDATE
DELETE
CREATE TABLE
DROP TABLE
execute()
ResultSet
Un ResultSet contient les lignes retournées par une requête SELECT.
Le curseur est positionné avant la première ligne. Il faut appeler next() pour passer à la ligne suivante.
next()
ResultSet resultat = instruction.executeQuery( "SELECT nom, prenom, age FROM apprenants" ); int i = 1; while (resultat.next()) { String nom = resultat.getString("nom"); String prenom = resultat.getString("prenom"); int age = resultat.getInt("age"); System.out.println("Ligne " + i + " = " + nom + " " + prenom + " " + age); i++; } resultat.close(); instruction.close(); connexion.close();
getString("nomColonne")
getInt("nomColonne")
getDouble("nomColonne")
getDate("nomColonne")
getBoolean("nomColonne")
On peut aussi accéder par numéro de colonne :
int id = resultat.getInt(1); String nom = resultat.getString(2);
C’est parfois un peu plus rapide, mais moins lisible.
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class TestSelectPostgres { public static void main(String[] args) { String url = "jdbc:postgresql://localhost:5432/pratique"; String utilisateur = "postgres"; String motDePasse = "postgres"; try ( Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse); Statement statement = connexion.createStatement(); ResultSet resultat = statement.executeQuery("SELECT id, nom, prenom FROM apprenants") ) { while (resultat.next()) { int id = resultat.getInt("id"); String nom = resultat.getString("nom"); String prenom = resultat.getString("prenom"); System.out.println(id + " - " + nom + " - " + prenom); } } catch (Exception e) { e.printStackTrace(); } } }
Ici, on utilise try-with-resources, ce qui est préférable : les ressources JDBC sont fermées automatiquement.
Pour un INSERT, UPDATE ou DELETE, on utilise généralement executeUpdate().
import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; public class TestInsertPostgres { public static void main(String[] args) { String url = "jdbc:postgresql://localhost:5432/pratique"; String utilisateur = "postgres"; String motDePasse = "postgres"; try ( Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse); Statement statement = connexion.createStatement() ) { int nbLignes = statement.executeUpdate( "INSERT INTO apprenants(nom, prenom, age) VALUES ('Durand', 'Paul', 28)" ); System.out.println("Nombre de lignes modifiées : " + nbLignes); } catch (Exception e) { e.printStackTrace(); } } }
Les requêtes paramétrées sont très importantes en JDBC.
Pourquoi les utiliser ?
Les paramètres sont représentés par des ? dans la requête SQL.
?
PreparedStatement instruction = connexion.prepareStatement( "UPDATE apprenants SET region = ? WHERE age = ?" ); instruction.setString(1, "Île-de-France"); instruction.setInt(2, 45); instruction.executeUpdate();
PreparedStatement instruction = connexion.prepareStatement( "SELECT nom, prenom FROM apprenants WHERE age >= ?" ); instruction.setInt(1, 18); ResultSet resultat = instruction.executeQuery();
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class TestPreparedStatementPostgres { public static void main(String[] args) { String url = "jdbc:postgresql://localhost:5432/pratique"; String utilisateur = "postgres"; String motDePasse = "postgres"; String sql = "SELECT nom, prenom FROM apprenants WHERE region = ?"; try ( Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse); PreparedStatement stm = connexion.prepareStatement(sql) ) { stm.setString(1, "Île-de-France"); try (ResultSet resultat = stm.executeQuery()) { while (resultat.next()) { String nom = resultat.getString("nom"); String prenom = resultat.getString("prenom"); System.out.println("Nom : " + nom + " | Prénom : " + prenom); } } } catch (Exception e) { e.printStackTrace(); } } }
PreparedStatement instruction = connexion.prepareStatement( "UPDATE apprenants SET region = ? WHERE age = ?" ); instruction.setString(1, "Île-de-France"); instruction.setInt(2, 45); int nbLignes = instruction.executeUpdate(); System.out.println(nbLignes + " ligne(s) mise(s) à jour.");
1
setString()
setInt()
setDouble()
setDate()
Exemple :
instruction.setString(1, "Martin"); instruction.setInt(2, 32);
Dans votre ancien support, on utilisait :
String creerBD = "CREATE SCHEMA IF NOT EXISTS `pratique` DEFAULT CHARACTER SET utf8 ";
Cette syntaxe est spécifique à MySQL et ne convient pas à PostgreSQL.
String creerSchema = "CREATE SCHEMA IF NOT EXISTS pratique"; statement.executeUpdate(creerSchema);
String sql = """ CREATE TABLE IF NOT EXISTS apprenants ( id SERIAL PRIMARY KEY, nom VARCHAR(100) NOT NULL, prenom VARCHAR(100) NOT NULL, age INTEGER, region VARCHAR(100) ) """; statement.executeUpdate(sql);
En pratique, on crée souvent la base PostgreSQL via :
psql
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class DemoJdbcPostgres { public static void main(String[] args) { String url = "jdbc:postgresql://localhost:5432/pratique"; String utilisateur = "postgres"; String motDePasse = "postgres"; String createTable = """ CREATE TABLE IF NOT EXISTS apprenants ( id SERIAL PRIMARY KEY, nom VARCHAR(100) NOT NULL, prenom VARCHAR(100) NOT NULL, age INTEGER ) """; String insertData = """ INSERT INTO apprenants(nom, prenom, age) VALUES ('Dupont', 'Alice', 25) """; String selectData = "SELECT id, nom, prenom, age FROM apprenants"; try ( Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse); Statement statement = connexion.createStatement() ) { statement.executeUpdate(createTable); statement.executeUpdate(insertData); try (ResultSet rs = statement.executeQuery(selectData)) { while (rs.next()) { System.out.println( rs.getInt("id") + " | " + rs.getString("nom") + " | " + rs.getString("prenom") + " | " + rs.getInt("age") ); } } } catch (Exception e) { e.printStackTrace(); } } }
Le concept reste le même avec JDBC, mais la syntaxe SQL côté base dépend du SGBD.
En PostgreSQL, on utilise souvent :
SELECT nom_fonction(...)
La classe JDBC utilisée est toujours CallableStatement.
CallableStatement appelProcedure = connexion.prepareCall("{ call ma_procedure(?) }");
CallableStatement appelFonction = connexion.prepareCall("{ ? = call ma_fonction(?) }");
En pratique, avec PostgreSQL, certains appels passent aussi par une requête SQL classique selon le type de fonction utilisé.
Par défaut, JDBC fonctionne en mode autocommit.
Cela signifie qu’après chaque requête SQL, la modification est automatiquement validée.
Ce mode convient à des traitements simples, mais devient risqué dès qu’une opération logique doit être réalisée en plusieurs étapes.
Exemple classique :
Si la première requête réussit et que la seconde échoue, il faut revenir en arrière pour éviter une incohérence.
Connection
getAutoCommit()
setAutoCommit(false)
commit()
rollback()
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class TransactionPostgres { public static void main(String[] args) { String url = "jdbc:postgresql://localhost:5432/banque"; String utilisateur = "postgres"; String motDePasse = "postgres"; Connection connexion = null; try { connexion = DriverManager.getConnection(url, utilisateur, motDePasse); connexion.setAutoCommit(false); try (Statement stm = connexion.createStatement()) { stm.executeUpdate( "UPDATE compte SET montant = montant - 100 WHERE num_compte = 100001" ); stm.executeUpdate( "UPDATE compte SET montant = montant + 100 WHERE num_compte = 100002" ); } connexion.commit(); System.out.println("Transaction validée."); } catch (SQLException e) { System.out.println("Erreur : annulation de la transaction."); e.printStackTrace(); if (connexion != null) { try { connexion.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } } finally { if (connexion != null) { try { connexion.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
Voici les adaptations principales apportées au support initial.
MySQL :
com.mysql.jdbc.Driver
PostgreSQL :
org.postgresql.Driver
jdbc:mysql://localhost:3306/ma_base
jdbc:postgresql://localhost:5432/ma_base
La syntaxe MySQL avec DEFAULT CHARACTER SET utf8 ne s’applique pas ici.
DEFAULT CHARACTER SET utf8
En PostgreSQL, on rencontre souvent :
SERIAL
ou aujourd’hui plus explicitement :
GENERATED ALWAYS AS IDENTITY
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
Évitez les concaténations SQL quand des valeurs viennent de l’utilisateur.
try-with-resources
Cela évite les oublis de fermeture de ressources.
Dans une vraie application, le code JDBC ne doit pas être écrit en vrac dans main().
main()
Il vaut mieux créer :
Une erreur SQL doit être affichée clairement pendant le développement.
Avant de les écrire en Java, testez-les dans :
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionFactory { private static final String URL = "jdbc:postgresql://localhost:5432/pratique"; private static final String USER = "postgres"; private static final String PASSWORD = "postgres"; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }
Ensuite, dans vos autres classes :
try (Connection connexion = ConnectionFactory.getConnection()) { // traitement JDBC }
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class ApprenantDao { public List<String> listerNoms() { List<String> noms = new ArrayList<>(); String sql = "SELECT nom FROM apprenants ORDER BY nom"; try ( Connection connexion = ConnectionFactory.getConnection(); PreparedStatement ps = connexion.prepareStatement(sql); ResultSet rs = ps.executeQuery() ) { while (rs.next()) { noms.add(rs.getString("nom")); } } catch (Exception e) { e.printStackTrace(); } return noms; } }
Créez un programme Java qui :
Créez en Java une table apprenants contenant :
apprenants
id
nom
prenom
age
Ajoutez 3 apprenants dans la table.
Affichez tous les apprenants avec un SELECT.
Affichez uniquement les apprenants dont l’âge est supérieur ou égal à une valeur donnée.
Modifiez la région d’un apprenant à l’aide d’un PreparedStatement.
Simulez un virement entre deux comptes avec commit() et rollback().
JDBC est une technologie fondamentale pour comprendre comment une application Java communique avec une base de données relationnelle.
Même si, dans les projets modernes, on utilise souvent des outils plus évolués comme :
la maîtrise de JDBC reste précieuse, car elle permet de :
Avec PostgreSQL, JDBC reste une solution robuste, claire et très formatrice.
Les exemples de ce support ont volontairement été simplifiés pour faciliter l’apprentissage.
Dans une application réelle, on évitera de tout écrire dans la méthode main(). On organisera le code en plusieurs classes, par exemple :
C’est précisément ce qui permet de passer d’un simple test JDBC à une vraie application professionnelle.