
Intégration de Liquibase avec Spring Boot
Découvrez comment utiliser Liquibase avec Spring Boot pour une gestion avancée des migrations de schéma de base de données via des changelogs structurés (XML, YAML, JSON, SQL).
Liquibase : Une approche structurée de la migration
Tout comme Flyway, Liquibase est un outil open-source de premier plan dédié à la gestion des migrations de schéma de base de données. Il permet de suivre, versionner et appliquer les changements de manière fiable et automatisée à travers différents environnements. L'objectif principal est d'assurer la cohérence du schéma de la base de données avec le code applicatif qui l'utilise.
L'approche de Liquibase diffère légèrement de celle de Flyway. Au lieu de se baser principalement sur des scripts SQL versionnés, Liquibase utilise des fichiers changelog, le plus souvent écrits en XML, YAML ou JSON (bien qu'il supporte aussi le SQL formaté). Ces changelogs décrivent les changements de manière plus abstraite (par exemple, "créer une table", "ajouter une colonne"), permettant potentiellement une meilleure portabilité entre différentes bases de données (Liquibase génère le SQL approprié pour la base cible).
Spring Boot offre une intégration transparente avec Liquibase, permettant d'exécuter automatiquement les migrations nécessaires au démarrage de l'application.
Ajouter la dépendance Liquibase
Pour intégrer Liquibase, commencez par ajouter la dépendance liquibase-core à votre projet. Comme pour Flyway, Spring Boot gère généralement la version via son BOM.
Avec Maven (pom.xml) :
org.liquibase
liquibase-core
Avec Gradle (build.gradle) :
implementation 'org.liquibase:liquibase-core'
// Assurez-vous d'avoir aussi une dépendance pour l'accès aux données
// (ex: implementation 'org.springframework.boot:spring-boot-starter-data-jpa')
// et le driver JDBC (ex: runtimeOnly 'org.postgresql:postgresql')
Une DataSource configurée dans votre application (via les propriétés `spring.datasource.*`) est également requise pour que Liquibase puisse se connecter à la base de données.
Auto-configuration et fonctionnement par défaut
Si liquibase-core est détecté sur le classpath et qu'une DataSource est disponible, Spring Boot auto-configure et exécute Liquibase au démarrage de l'application, avant l'initialisation de JPA/Hibernate.
Le processus par défaut est le suivant :
- Spring Boot crée une instance de
liquibase.integration.spring.SpringLiquibase. - Liquibase recherche un fichier changelog principal dans un emplacement par défaut sur le classpath.
- Il se connecte à la base de données et vérifie l'état des migrations en consultant ses tables de métadonnées (par défaut `DATABASECHANGELOG` et `DATABASECHANGELOGLOCK`).
- Il identifie et applique tous les `changeSet` (unités de changement) définis dans le changelog qui n'ont pas encore été exécutés.
Par défaut, Spring Boot recherche le fichier changelog principal à l'emplacement classpath:db/changelog/db.changelog-master.yaml ou classpath:db/changelog/db.changelog-master.xml (ou .json, .sql). Vous devez donc généralement créer le dossier src/main/resources/db/changelog/ et y placer votre fichier changelog maître.
Format des 'changelogs' Liquibase (XML, YAML, JSON, SQL)
Le fichier changelog est le coeur de Liquibase. Il contient une liste de changeSet, où chaque changeSet représente une unité atomique de changement de schéma.
Chaque changeSet doit avoir un attribut id et un attribut author uniques (la combinaison id + author doit être unique à travers tous les changelogs). Liquibase utilise ces identifiants pour savoir quels changeSets ont déjà été appliqués.
A l'intérieur d'un changeSet, vous décrivez les changements en utilisant les balises/clés fournies par Liquibase (ex: createTable, addColumn, addForeignKeyConstraint) ou en incluant directement du SQL (via la balise ou équivalent).
Exemple (YAML - `src/main/resources/db/changelog/db.changelog-master.yaml`) :
databaseChangeLog:
- changeSet:
id: 1
author: app_dev
changes:
- createTable:
tableName: app_user
columns:
- column:
name: id
type: BIGINT
autoIncrement: true # Ou gérer via sequence
constraints:
primaryKey: true
nullable: false
- column:
name: username
type: VARCHAR(100)
constraints:
unique: true
nullable: false
- column:
name: email
type: VARCHAR(150)
constraints:
unique: true
- changeSet:
id: 2
author: app_dev
changes:
- addColumn:
tableName: app_user
columns:
- column:
name: registration_date
type: TIMESTAMP
- changeSet:
id: 3 # Exemple avec du SQL direct
author: dba
changes:
- sql:
sql: INSERT INTO app_user (username, email) VALUES ('admin', 'admin@example.com');
# Attention à l'idempotence si nécessaire
# Inclure d'autres fichiers changelog
# - include:
# file: db/changelog/changes/changelog-v1.1.yaml
Exemple (XML - `src/main/resources/db/changelog/db.changelog-master.xml`) :
L'utilisation de formats comme XML ou YAML permet à Liquibase de générer le SQL spécifique à la base de données cible, offrant une meilleure portabilité que les scripts SQL purs.
Configuration via `application.properties`/`yml`
De nombreuses options de configuration sont disponibles pour adapter le comportement de Liquibase :
# application.properties
# Activer/Désactiver Liquibase (défaut: true si liquibase-core est présent)
spring.liquibase.enabled=true
# Chemin vers le fichier changelog maître (défaut: classpath:/db/changelog/db.changelog-master.yaml ou .xml)
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-main.xml
# Contexte(s) à exécuter (permet d'exécuter des changeSets spécifiques, ex: pour tests)
# spring.liquibase.contexts=test,dev
# Label(s) à exécuter (autre mécanisme de filtrage)
# spring.liquibase.labels=v1.0
# Nom de la table de log (défaut: DATABASECHANGELOG)
# spring.liquibase.database-change-log-table=my_changelog
# Nom de la table de verrou (défaut: DATABASECHANGELOGLOCK)
# spring.liquibase.database-change-log-lock-table=my_changelog_lock
# Schéma par défaut où exécuter Liquibase
# spring.liquibase.default-schema=public
# Drop les objets de la BDD au démarrage avant migration (TRES DANGEREUX, pour tests uniquement)
# spring.liquibase.drop-first=false
# Exécuter une mise à jour "à vide" pour marquer les changeSets comme exécutés sans les appliquer
# spring.liquibase.test-rollback-on-update=false
Les contextes (`contexts`) et les labels (`labels`) sont des fonctionnalités puissantes de Liquibase pour exécuter sélectivement des `changeSet` en fonction de l'environnement ou d'autres critères.
Coordination avec JPA/Hibernate
Comme pour Flyway, il est essentiel de coordonner Liquibase avec JPA/Hibernate pour éviter les conflits de gestion de schéma. La recommandation est la même :
# application.properties
spring.jpa.hibernate.ddl-auto=validate # ou none
Utilisez validate pour que Hibernate vérifie la cohérence entre le schéma (géré par Liquibase) et vos entités au démarrage, ou none pour désactiver toute action de Hibernate sur le schéma (option la plus sûre en production). Evitez absolument create, create-drop, et update lorsque Liquibase est actif.
Liquibase vs Flyway : Lequel choisir ?
Le choix entre Liquibase et Flyway dépend souvent des préférences de l'équipe et des besoins spécifiques :
- Flyway : Préféré si vous êtes à l'aise avec l'écriture directe de SQL et que vous voulez une approche simple basée sur des scripts SQL versionnés.
- Liquibase : Préféré si vous souhaitez décrire les changements de manière plus abstraite (XML/YAML/JSON), si la portabilité entre différentes bases de données est un critère important, ou si vous avez besoin de fonctionnalités avancées comme les contextes, les labels, les preConditions ou les rollbacks automatiques (Liquibase peut générer des instructions de rollback pour certains types de changements).
Les deux outils sont excellents et bien intégrés à Spring Boot.
Conclusion : Une gestion structurée et fiable du schéma
Liquibase, intégré à Spring Boot, fournit une solution puissante et flexible pour automatiser et versionner les migrations de votre schéma de base de données. En utilisant des fichiers changelog structurés, il permet une gestion fiable des évolutions de la base, assure la cohérence entre les environnements et facilite le travail collaboratif. Son approche abstraite des changements peut également offrir une meilleure portabilité et des fonctionnalités avancées par rapport aux scripts SQL purs.