Aller au contenu

Découverte de JDBC avec PostgreSQL

Qu’est-ce que JDBC ?

Introduction

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.


Le pilote JDBC PostgreSQL

Pour communiquer avec PostgreSQL depuis Java, il faut ajouter le pilote JDBC PostgreSQL au projet.

1) Avec Maven

C’est la méthode recommandée.

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.5</version>
</dependency>

2) Sans Maven

Vous pouvez télécharger le fichier .jar du pilote PostgreSQL puis l’ajouter au projet Eclipse ou IntelliJ.

Le nom du fichier ressemble généralement à ceci :

postgresql-42.7.5.jar

3) Ajout manuel dans Eclipse


Exemple d’architecture JDBC

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 :


Le package 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 :

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;

Les grandes étapes d’un traitement JDBC

Quel que soit le SGBD, les étapes sont toujours quasiment les mêmes :

  1. Charger éventuellement le pilote JDBC.
  2. Ouvrir une connexion à la base de données.
  3. Préparer la requête SQL.
  4. Exécuter la requête.
  5. Exploiter les résultats si la requête retourne des données.
  6. Fermer les ressources.

1) Chargement du pilote JDBC PostgreSQL

Historiquement, on chargeait explicitement le pilote avec Class.forName(...).

Class.forName("org.postgresql.Driver");

Remarque importante

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.

Exemple

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();
}

2) Paramètres de connexion PostgreSQL

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";

Explication de l’URL

jdbc:postgresql://localhost:5432/pratique

Attention : le port PostgreSQL par défaut est généralement 5432.


3) Établir la connexion

Une fois le pilote disponible, on ouvre la connexion grâce à DriverManager.getConnection(...).

Syntaxe générale

Connection connexion = DriverManager.getConnection(url, utilisateur, motDePasse);

Exemple complet

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();
        }
    }
}

4) Passage d’une requête SQL

Lorsque la connexion est établie, on peut envoyer des requêtes SQL à PostgreSQL.

Il existe trois grandes manières de travailler :


Les requêtes directes avec Statement

Création d’un objet Statement

Statement instruction = connexion.createStatement();

Exécution d’une requête SELECT

ResultSet resultat = instruction.executeQuery(
    "SELECT nom, prenom, age FROM apprenants"
);

Les trois méthodes principales


5) Exploitation des résultats avec 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.

Exemple

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();

Méthodes de lecture fréquentes

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.


Exemple complet : requête directe avec PostgreSQL

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.


Exemple de requête sans résultat

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 précompilées avec PreparedStatement

Les requêtes paramétrées sont très importantes en JDBC.

Pourquoi les utiliser ?

Principe

Les paramètres sont représentés par des ? dans la requête SQL.

Exemple simple

PreparedStatement instruction = connexion.prepareStatement(
    "UPDATE apprenants SET region = ? WHERE age = ?"
);

instruction.setString(1, "Île-de-France");
instruction.setInt(2, 45);

instruction.executeUpdate();

Exemple : sélection paramétrée

PreparedStatement instruction = connexion.prepareStatement(
    "SELECT nom, prenom FROM apprenants WHERE age >= ?"
);

instruction.setInt(1, 18);
ResultSet resultat = instruction.executeQuery();

Exemple complet avec PreparedStatement

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();
        }
    }
}

Exemple avec deux paramètres

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.");

Ce qu’il faut retenir sur PreparedStatement

Exemple :

instruction.setString(1, "Martin");
instruction.setInt(2, 32);

Création d’une base et d’une table avec PostgreSQL

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.

En PostgreSQL

Exemple de création d’un schéma PostgreSQL

String creerSchema = "CREATE SCHEMA IF NOT EXISTS pratique";
statement.executeUpdate(creerSchema);

Exemple de création d’une table PostgreSQL

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);

Remarque pédagogique

En pratique, on crée souvent la base PostgreSQL via :


Exemple complet : création de table + insertion + lecture

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();
        }
    }
}

Les procédures stockées et fonctions avec PostgreSQL

Point important

Le concept reste le même avec JDBC, mais la syntaxe SQL côté base dépend du SGBD.

En PostgreSQL, on utilise souvent :

La classe JDBC utilisée est toujours CallableStatement.

Exemple générique

CallableStatement appelProcedure = connexion.prepareCall("{ call ma_procedure(?) }");

Exemple générique pour une fonction

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é.


Le contrôle des transactions

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.

Méthodes importantes de Connection


Exemple de transaction sécurisée avec PostgreSQL

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();
                }
            }
        }
    }
}

Ce qu’il faut comprendre


Différences importantes entre MySQL et PostgreSQL

Voici les adaptations principales apportées au support initial.

1) Pilote JDBC

MySQL :

com.mysql.jdbc.Driver

PostgreSQL :

org.postgresql.Driver

2) URL JDBC

MySQL :

jdbc:mysql://localhost:3306/ma_base

PostgreSQL :

jdbc:postgresql://localhost:5432/ma_base

3) Création de base / schéma

La syntaxe MySQL avec DEFAULT CHARACTER SET utf8 ne s’applique pas ici.

4) Types auto-incrémentés

En PostgreSQL, on rencontre souvent :

SERIAL

ou aujourd’hui plus explicitement :

GENERATED ALWAYS AS IDENTITY

Exemple :

id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY

Bonnes pratiques à retenir

1) Préférez PreparedStatement

Évitez les concaténations SQL quand des valeurs viennent de l’utilisateur.

2) Utilisez try-with-resources

Cela évite les oublis de fermeture de ressources.

3) Isolez l’accès aux données

Dans une vraie application, le code JDBC ne doit pas être écrit en vrac dans main().

Il vaut mieux créer :

4) Gérez correctement les exceptions

Une erreur SQL doit être affichée clairement pendant le développement.

5) Testez vos requêtes directement dans PostgreSQL

Avant de les écrire en Java, testez-les dans :


Exemple de classe utilitaire de connexion

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
}

Mini exemple DAO

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;
    }
}

Exercices pratiques proposés

Exercice 1 — Tester la connexion PostgreSQL

Créez un programme Java qui :

Exercice 2 — Créer une table

Créez en Java une table apprenants contenant :

Exercice 3 — Insérer des données

Ajoutez 3 apprenants dans la table.

Exercice 4 — Lire les données

Affichez tous les apprenants avec un SELECT.

Exercice 5 — Requête paramétrée

Affichez uniquement les apprenants dont l’âge est supérieur ou égal à une valeur donnée.

Exercice 6 — Mise à jour

Modifiez la région d’un apprenant à l’aide d’un PreparedStatement.

Exercice 7 — Transaction

Simulez un virement entre deux comptes avec commit() et rollback().


Conclusion

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.


Remarque

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.