Liquibase est un outil robuste pour la gestion des versions de schémas de base de données. Il utilise des fichiers de changelog pour décrire les modifications à appliquer au schéma de la base de données de manière traçable et reproductible. Lors de son exécution, Liquibase interagit avec deux tables principales dans la base de données cible pour suivre l'état des modifications et gérer les accès concurrents.
Tables de Suivi et de Verrouillage
Liquibase crée et maintient automatiquement deux tables essentielles dans votre base de données :
DATABASECHANGELOG: Cette table enregistre l'historique de toutes les modifications (changeSet) qui ont été appliquées à la base de données. Chaque ligne correspond à unchangeSetexécuté, incluatn son ID, son auteur, le nom du fichier changelog d'origine, la date d'exécution, et un checksum (MD5SUM) pour détecter les modifications ultérieures duchangeSet. Avant d'exécuter unchangeSet, Liquibase vérifie cette table pour s'assurer qu'il n'a pas déjà été appliqué (à moins que l'attributrunAlwaysne soit spécifié).DATABASECHANGELOGLOCK: Cette table est utilisée pour implémenter un mécanisme de verrouillage distribué. Elle garantit qu'une seule instance de Liquibase peut exécuter des migrations à un moment donné, empêchant ainsi les conflits et les corruptions de schéma lors d'exécutions parallèles. La table contient généralement une seule ligne avec un champLOCKEDqui indique si un processus Liquibase détient actuellement le verrou.
Gestion des Verrous de Changelog
Il arrive que Liquibase affiche un message INFO ... Liquibase: Waiting for changelog lock.... Cela signifie qu'une autre instance de Liquibase (ou une instance précédente qui s'est terminée de manière anormale) détient toujours le verrou de la base de données. Pour résoudre ce problème, il est parfois nécessaire de libérer manuellement ce verrou. Il est crucial de s'assurer qu'aucune autre instance de Liquibase n'est en cours d'exécution avant de procéder à cette manipulation.
Pour vérifier l'état du verrou :
-- Affiche l'état actuel du verrou
SELECT * FROM DATABASECHANGELOGLOCK;
Si le champ LOCKED est à 1, le verou est actif. Pour le libérer manuellement (à utiliser avec prudence) :
-- Libère manuellement le verrou du changelog
-- Assurez-vous qu'aucun autre processus Liquibase n'est en cours d'exécution
UPDATE DATABASECHANGELOGLOCK
SET LOCKED=0, LOCKGRANTED=NULL, LOCKEDBY=NULL
WHERE ID=1; -- L'ID du verrou est généralement 1
Structure des Fichiers Changelog
Un fichier changelog principal est un fichier XML qui contient une balise racine <databaseChangeLog>. Il peut directement contenir des <changeSet> ou inclure d'autres fichiers changelog. Les schémas XML (xmlns et xsi:schemaLocation) sont essentiels pour la validation et l'autocomplétion.
Balises d'Inclusion : <include> et <includeAll>
Liquibase offre des mécanismes pour organiser les changelogs en plusieurs fichiers, ce qui est idéal pour les grands projets :
<include>: Cette balise permet d'inclure un fichier changelog spécifique. L'attributfileindique le chemin vers le fichier à inclure. Si l'attributrelativeToChangelogFileest défini àtrue, le chemin spécifié dansfileest résolu par rapport à l'emplacement du changelog appelant, et non par rapport au classpath. La valeur par défaut estfalse.<includeAll>: Cette balise est utilisée pour inclure tous les fichiers changelog trouvés dans un répertoire donné. L'attributpathspécifie le chemin du répertoire. Liquibase inclura tous les fichiers reconnus (XML, YAML, JSON, SQL) dans ce répertoire, en les triant généralement par ordre alphanumérique pour déterminer l'ordre d'exécution.
Exemple de fichier SQL inclus via <include> :
-- liquibase formatted sql
-- changeset dev:20230105_user_profile_table failOnError:true dbms:postgresql
-- Commentaire : Ajout de la table pour les profils utilisateurs
CREATE TABLE user_profiles (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL UNIQUE,
display_name VARCHAR(100),
bio TEXT
);
Inclusion de ce fichier dans un changelog XML principal :
<include file="db/changelogs/20230105_create_user_profile.sql" relativeToChangelogFile="true" />
Exemple d'inclusion de tous les fichiers d'un répertoire :
<includeAll path="db/changelogs/app_features/" />
Exemple de Fichier Changelog XML Principal
Voici la structure typique d'un fichier changelog XML principal, incluant les déclarations de namespace et un exemple de changeSet initial, ainsi qu'une référence à un autre fichier de modification :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet author="app_dev" id="20230101_base_schema-1">
<comment>Mise en place de la structure initiale du schéma de base de données.</comment>
<!-- Ce changeSet peut contenir des modifications directes ou être un point de référence -->
</changeSet>
<include file="changelogs/20230106_add_product_table.sql" relativeToChangelogFile="true" />
<includeAll path="changelogs/data_migrations/" />
</databaseChangeLog>