Aller au contenu principal

TP4.1 - Intégration PostgreSQL avec Jakarta Persistence

Migration vers une Base de Données de Production​

Objectifs​

Ce travail pratique vous permettra de:

  • Intégrer PostgreSQL avec Spring Boot
  • Utiliser Jakarta Persistence (JPA) pour la persistance des données
  • Configurer Hibernate comme ORM
  • Créer et gérer une base de données relationnelle
  • Comprendre la différence entre Jakarta et Javax Persistence
  • Maîtriser la configuration avec application.properties et application.yml

Table des Matières​

  1. Rappel Rapide
  2. Ajout de la Base de Données
  3. Test avec PostgreSQL
  4. Exercice 1: Javax Persistence
  5. Exercice 2: Configuration YAML
  6. Exercice 3: Lombok
  7. Exercice 4: Recréation Automatique
  8. Exercice 5: Autre Base de Données

1. Rappel Rapide​

Contexte​

Dans les TPs précédents, nous avons créé une application CRUD complète avec H2. Maintenant, nous allons migrer vers PostgreSQL, une base de données relationnelle professionnelle adaptée à la production.

Objectifs de ce TP​

  1. Migrer de H2 vers PostgreSQL - Passer d'une base embarquée à une base de production
  2. Utiliser Jakarta Persistence (JPA) - Mapper les objets Java vers les tables SQL
  3. Configurer PostgreSQL - Installer et configurer une base de données professionnelle

Prérequis​

  • TP3 (Architecture CRUD) complété
  • PostgreSQL installé (version 12 ou supérieure)
  • pgAdmin ou DBeaver pour gérer PostgreSQL
  • Visual Studio Code avec extensions Java

2. Ajout de la Base de Données​

2.1 Ajout des Dépendances dans pom.xml​

Ouvrez votre fichier pom.xml et ajoutez les deux dépendances suivantes dans la section <dependencies>:

<!-- Driver PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

<!-- Spring Data JPA (inclut Jakarta Persistence) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Explication:

DépendanceRôle
postgresqlDriver JDBC pour se connecter à PostgreSQL
spring-boot-starter-data-jpaInclut JPA, Hibernate, et Spring Data

Note: Après l'ajout, VS Code vous proposera de recharger le projet Maven. Acceptez ou exécutez:

mvn clean install -DskipTests

2.2 Configuration de application.properties​

Créez ou modifiez le fichier src/main/resources/application.properties:

# URL de connexion à la base de données
spring.datasource.url=jdbc:postgresql://localhost:5432/greeting_db?useSSL=false

# Credentials de connexion
spring.datasource.username=postgres
spring.datasource.password=postgres

# Configuration Hibernate
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

# Stratégie de génération du schéma
spring.jpa.hibernate.ddl-auto=create

# Afficher les requêtes SQL (utile pour le développement)
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

Explication des propriétés:

PropriétéDescriptionValeurs possibles
spring.datasource.urlURL de connexion JDBCFormat: jdbc:postgresql://host:port/database
spring.datasource.usernameNom d'utilisateur PostgreSQLPar défaut: postgres
spring.datasource.passwordMot de passe PostgreSQLÀ adapter selon votre installation
spring.jpa.hibernate.ddl-autoStratégie de création du schémanone, validate, update, create, create-drop
spring.jpa.show-sqlAfficher les requêtes SQL dans la consoletrue ou false

Valeurs de ddl-auto:

Important: Changez greeting_db par le nom de votre base de données si nécessaire.

2.3 Annotation de l'Entité Greeting.java​

Modifiez la classe Greeting.java pour en faire une entité JPA:

package com.example.demo;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "greeting")
public class Greeting {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "content", nullable = false)
private String content;

// Constructeur par défaut (requis par JPA)
public Greeting() {
}

// Constructeur avec paramètres
public Greeting(Long id, String content) {
this.id = id;
this.content = content;
}

// Getters et Setters
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

Explication des annotations:

AnnotationRôle
@EntityMarque la classe comme entité JPA (mappée vers une table)
@Table(name = "greeting")Spécifie le nom de la table SQL
@IdMarque le champ comme clé primaire
@GeneratedValue(strategy = GenerationType.IDENTITY)Auto-incrémentation de l'ID
@Column(name = "content", nullable = false)Configuration de la colonne SQL

Architecture JPA:

2.4 Création du Repository​

Créez une interface GreetingRepository.java dans le package com.example.demo:

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface GreetingRepository extends JpaRepository<Greeting, Long> {
// Spring Data JPA génère automatiquement l'implémentation
// Méthodes disponibles: save(), findAll(), findById(), delete(), etc.
}

Méthodes générées automatiquement:

MéthodeDescription
save(Greeting g)Sauvegarder ou mettre à jour
findAll()Récupérer toutes les entrées
findById(Long id)Récupérer par ID
deleteById(Long id)Supprimer par ID
count()Compter les entrées

2.5 Modification du Controller​

Modifiez GreetingController.java pour utiliser le repository:

package com.example.demo;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();

private final GreetingRepository greetingRepository;

public GreetingController(GreetingRepository greetingRepository) {
this.greetingRepository = greetingRepository;
}

@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value="name") String name) {
Greeting greeting = new Greeting(
counter.incrementAndGet(),
String.format(template, name)
);

// Sauvegarder dans la base de données
return greetingRepository.save(greeting);
}
}

Flux de données:

2.6 Création de la Base de Données PostgreSQL​

Option A: Avec pgAdmin​

  1. Ouvrir pgAdmin

  2. Créer un utilisateur (optionnel):

    • Clic droit sur "Login/Group Roles"
    • "Create" → "Login/Group Role"
    • Onglet "General": Name = postgres
    • Onglet "Definition": Password = postgres
    • Onglet "Privileges": Cocher "Can login?" et "Create databases?"
    • Sauvegarder
  3. Créer la base de données:

    • Clic droit sur "Databases"
    • "Create" → "Database"
    • Database name: greeting_db
    • Owner: postgres
    • Sauvegarder

Option B: Avec SQL (ligne de commande)​

-- Créer la base de données
CREATE DATABASE greeting_db;

-- Créer l'utilisateur (si nécessaire)
CREATE USER postgres WITH PASSWORD 'postgres';

-- Accorder les privilèges
GRANT ALL PRIVILEGES ON DATABASE greeting_db TO postgres;

Pour exécuter ces commandes:

# Windows
psql -U postgres

# macOS/Linux
sudo -u postgres psql

3. Test avec PostgreSQL​

3.1 Vérification de la Configuration​

Avant de lancer l'application, vérifiez:

Checklist:

  • PostgreSQL est démarré
  • La base de données greeting_db existe
  • L'utilisateur postgres a les bons privilèges
  • Le fichier application.properties est correct
  • La classe Greeting a l'annotation @Entity
  • L'interface GreetingRepository est créée
  • Le GreetingController utilise le repository

3.2 Lancement de l'Application​

Dans VS Code:

Méthode 1: Via le Terminal​

# Nettoyer et compiler
mvn clean install

# Lancer l'application
mvn spring-boot:run

Méthode 2: Via l'Interface​

  1. Ouvrir GreetingApplication.java
  2. Cliquer sur "Run" au-dessus de la méthode main
  3. Ou appuyer sur F5

Logs attendus:

Hibernate: drop table if exists greeting cascade
Hibernate: create table greeting (id bigserial not null, content varchar(255) not null, primary key (id))
Started GreetingApplication in X.XXX seconds

3.3 Test des Endpoints​

Test 1: Créer un greeting

http://localhost:8080/greeting?name=John

Réponse attendue:

{
"id": 1,
"content": "Hello, John!"
}

Test 2: Créer plusieurs greetings

http://localhost:8080/greeting?name=Alice
http://localhost:8080/greeting?name=Bob
http://localhost:8080/greeting?name=Charlie

3.4 Vérification dans PostgreSQL​

Avec pgAdmin:​

  1. Ouvrir pgAdmin
  2. Naviguer: Servers → PostgreSQL → Databases → greeting_db → Schemas → public → Tables
  3. Clic droit sur "greeting" → "View/Edit Data" → "All Rows"

Avec SQL:​

-- Se connecter à la base
\c greeting_db

-- Afficher toutes les entrées
SELECT * FROM greeting;

-- Résultat attendu:
-- id | content
-- ---+----------------
-- 1 | Hello, John!
-- 2 | Hello, Alice!
-- 3 | Hello, Bob!
-- 4 | Hello, Charlie!

3.5 Logs SQL dans la Console​

Grâce à spring.jpa.show-sql=true, vous verrez les requêtes SQL dans la console:

Hibernate: insert into greeting (content) values (?)

4. Exercice 1: Refaire avec Javax Persistence​

Énoncé​

Refaites le projet en utilisant Javax Persistence au lieu de Jakarta Persistence (ancienne version de JPA).

Objectif​

Comprendre la différence entre Jakarta et Javax Persistence.

Contexte Historique​

Instructions​

Étape 1: Modifier pom.xml

Ajoutez la dépendance Javax Persistence:

<!-- Ajout de Javax Persistence -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>

Étape 2: Modifier les imports dans Greeting.java

Remplacez:

import jakarta.persistence.*;

Par:

import javax.persistence.*;

Étape 3: Classe complète avec Javax

package com.example.demo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "greeting")
public class Greeting {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "content", nullable = false)
private String content;

public Greeting() {}

public Greeting(Long id, String content) {
this.id = id;
this.content = content;
}

// Getters et Setters
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

Étape 4: Tester

  1. Recompilez: mvn clean install -DskipTests
  2. Relancez l'application
  3. Vérifiez que tout fonctionne

Questions de Réflexion​

  1. Quelle est la différence majeure entre Javax et Jakarta Persistence?
  2. Pourquoi Jakarta est-il recommandé pour les nouveaux projets?
  3. Peut-on mélanger les deux dans le même projet?

5. Exercice 2: Configuration avec application.yml​

Énoncé​

Convertissez votre configuration application.properties en format YAML.

Objectif​

Maîtriser le format YAML pour la configuration Spring Boot.

Instructions​

Étape 1: Supprimer application.properties

Supprimez ou renommez le fichier application.properties.

Étape 2: Créer application.yml

Créez src/main/resources/application.yml:

spring:
datasource:
url: jdbc:postgresql://localhost:5432/greeting_db?useSSL=false
username: postgres
password: postgres

jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
jdbc:
lob:
non_contextual_creation: true
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true

Étape 3: Tester

Relancez l'application et vérifiez que tout fonctionne.

Comparaison​

application.properties:

spring.datasource.url=jdbc:postgresql://localhost:5432/greeting_db
spring.datasource.username=postgres
spring.jpa.hibernate.ddl-auto=create

application.yml:

spring:
datasource:
url: jdbc:postgresql://localhost:5432/greeting_db
username: postgres
jpa:
hibernate:
ddl-auto: create

Avantages du YAML:

  • Plus lisible pour les structures hiérarchiques
  • Moins de répétition
  • Format moderne

6. Exercice 3: Simplification avec Lombok​

Énoncé​

Supprimez les getters, setters et constructeurs manuels en utilisant Lombok.

Objectif​

Réduire le code boilerplate avec Lombok.

Prérequis​

Étape 1: Ajouter la dépendance Lombok dans pom.xml

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

Étape 2: Installer l'extension Lombok dans VS Code

  1. Extensions → Rechercher "Lombok"
  2. Installer "Lombok Annotations Support for VS Code"

Instructions​

Modifier Greeting.java:

package com.example.demo;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "greeting")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Greeting {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "content", nullable = false)
private String content;

// Lombok génère automatiquement:
// - Getters
// - Setters
// - toString()
// - equals() et hashCode()
// - Constructeur vide
// - Constructeur avec tous les arguments
}

Annotations Lombok:

AnnotationGénère
@DataGetters, Setters, toString, equals, hashCode
@NoArgsConstructorConstructeur vide
@AllArgsConstructorConstructeur avec tous les champs
@GetterSeulement les getters
@SetterSeulement les setters

Test​

  1. Recompilez
  2. Vérifiez que l'application fonctionne
  3. Les méthodes sont générées à la compilation

7. Exercice 4: Recréation Automatique de la Base​

Énoncé​

Configurez l'application pour qu'elle recrée automatiquement la base de données à chaque démarrage.

Objectif​

Comprendre les différentes stratégies de gestion du schéma.

Instructions​

Dans application.properties (ou application.yml):

spring.jpa.hibernate.ddl-auto=create-drop

ou

spring:
jpa:
hibernate:
ddl-auto: create-drop

Comparaison des Stratégies​

StratégieComportementUsage
noneAucune actionProduction
validateValide le schéma sans modifierProduction
updateMet à jour le schémaDéveloppement
createCrée le schéma au démarrageTests
create-dropCrée au démarrage, supprime à l'arrêtTests unitaires

Attention​

create-drop supprime toutes les données à l'arrêt de l'application!

Usage recommandé:

# Développement
spring:
jpa:
hibernate:
ddl-auto: update

# Production
spring:
jpa:
hibernate:
ddl-auto: validate

8. Exercice 5: Migration vers MySQL, SQL Server ou Oracle​

Énoncé​

Refaites l'intégration complète avec une autre base de données.

Choix de Base de Données​

Option A: MySQL​

Dépendance dans pom.xml:

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

Configuration application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/greeting_db?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update

Création de la base dans MySQL:

CREATE DATABASE greeting_db;
CREATE USER 'root'@'localhost' IDENTIFIED BY 'root';
GRANT ALL PRIVILEGES ON greeting_db.* TO 'root'@'localhost';
FLUSH PRIVILEGES;

Option B: SQL Server​

Dépendance dans pom.xml:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>

Configuration application.properties:

spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=greeting_db
spring.datasource.username=sa
spring.datasource.password=YourStrong@Password
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
spring.jpa.hibernate.ddl-auto=update

Création de la base dans SQL Server:

CREATE DATABASE greeting_db;
GO

ALTER LOGIN sa WITH PASSWORD = 'YourStrong@Password';
GO

USE greeting_db;
GO

Option C: Oracle​

Dépendance dans pom.xml:

<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>

Configuration application.properties:

spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=oracle
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect
spring.jpa.hibernate.ddl-auto=update

Création de la base dans Oracle:

CREATE USER greeting_user IDENTIFIED BY oracle;
GRANT ALL PRIVILEGES TO greeting_user;

Tableau Comparatif​

Base de DonnéesPort par DéfautDialect HibernateDifficulté
PostgreSQL5432PostgreSQLDialectFacile
MySQL3306MySQLDialectFacile
SQL Server1433SQLServerDialectMoyenne
Oracle1521Oracle12cDialectDifficile

Instructions Générales​

  1. Installer la base de données choisie
  2. Modifier pom.xml avec le bon driver
  3. Modifier application.properties avec la bonne configuration
  4. Créer la base de données et l'utilisateur
  5. Recompiler et tester

Résolution de Problèmes​

Problème 1: Connection Refused​

Symptôme:

org.postgresql.util.PSQLException: Connection to localhost:5432 refused

Solutions:

  1. Vérifier que PostgreSQL est démarré:

Windows:

# Dans Services, chercher PostgreSQL
services.msc

Linux:

sudo systemctl status postgresql
sudo systemctl start postgresql
  1. Vérifier le port dans postgresql.conf

Problème 2: Authentication Failed​

Symptôme:

PSQLException: FATAL: password authentication failed for user "postgres"

Solutions:

  1. Vérifier le mot de passe dans application.properties
  2. Réinitialiser le mot de passe:
ALTER USER postgres WITH PASSWORD 'nouveau_mot_de_passe';

Problème 3: Database Does Not Exist​

Symptôme:

PSQLException: FATAL: database "greeting_db" does not exist

Solution:

Créer la base de données:

CREATE DATABASE greeting_db;

Problème 4: Table Already Exists​

Symptôme:

Table "greeting" already exists

Solution:

Changer la stratégie DDL:

spring.jpa.hibernate.ddl-auto=update

Problème 5: Lombok Ne Fonctionne Pas​

Symptôme:

error: cannot find symbol
method getId()

Solutions:

  1. Installer l'extension Lombok dans VS Code
  2. Redémarrer VS Code
  3. Vérifier que la dépendance est dans pom.xml
  4. Recompiler: mvn clean install -DskipTests spring-boot:run

Questions de Révision​

  1. Quelle est la différence entre Jakarta et Javax Persistence?

  2. Que fait l'annotation @Entity?

  3. Quelle est la différence entre create, update et validate pour ddl-auto?

  4. Comment Spring Data JPA génère-t-il l'implémentation du repository?

  5. Que fait l'annotation @GeneratedValue(strategy = GenerationType.IDENTITY)?

  6. Pourquoi doit-on avoir un constructeur vide dans une entité JPA?

  7. Que génère l'annotation @Data de Lombok?

  8. Quelle configuration utiliser en production pour ddl-auto?


Livrables​

À remettre:

  1. Code source complet avec PostgreSQL fonctionnel
  2. Captures d'écran montrant:
    • L'application en cours d'exécution
    • Les données dans pgAdmin
    • Les requêtes SQL dans la console
  3. Au moins 2 exercices complétés
  4. Document de réponses aux questions de révision

Critères d'Évaluation​

CritèrePoints
Intégration PostgreSQL fonctionnelle25%
Entité Greeting correctement annotée20%
Repository créé et utilisé15%
Données persistées dans PostgreSQL20%
Exercices complétés10%
Questions de révision répondues10%
Total100%

Prochaines Étapes​

Dans le prochain TP, nous verrons:

  • TP3: Création d'une API CRUD complète
  • Operations: Create, Read, Update, Delete
  • Gestion des erreurs
  • Validation des données

Ressources Supplémentaires​

Documentation​

Tutoriels​


Retour au Module 2