• Contenu
  • Bas de page
logo ouidoulogo ouidoulogo ouidoulogo ouidou
  • Qui sommes-nous ?
  • Offres
    • 💻 Applications métier
    • 🤝 Collaboration des équipes
    • 🛡️ Sécurisation et optimisation du système d’information
    • 🔗 Transformation numérique
  • Expertises
    • 🖥️ Développement logiciel
    • ♾️ DevSecOps
    • ⚙️ Intégration de logiciels et négoce de licences
      • Atlassian : Jira, Confluence, Bitbucket…
      • Plateforme monday.com
      • GitLab
      • SonarQube
    • 📚​ Logiciel de CRM et de gestion
    • 🎨 UX/UI design
    • 🌐 Accessibilité Numérique
    • 🗂️​ Démarches simplifiées
    • 📝 Formations Atlassian
  • Références
  • Carrières
    • 🧐 Pourquoi rejoindre Ouidou ?
    • ✍🏻 Nous rejoindre
    • 👨‍💻 Rencontrer nos collaborateurs
    • 🚀 Grandir chez Ouidou
  • RSE
  • Ressources
    • 🗞️ Actualités
    • 🔍 Articles techniques
    • 📖 Livres blancs
    • 🎙️ Interviews Clients
Nous contacter
✕
Apprendre à maitriser les types utilitaires en Typescript
Apprendre à maitriser les types utilitaires en Typescript
13 juillet 2023
Plugins Figma – Améliorez votre productivité (partie 2)
Plugins Figma – Améliorez votre productivité (partie 2)
27 juillet 2023
Ressources > Articles techniques > Versionnez vos bases de données avec Liquibase

Versionnez vos bases de données avec Liquibase

Article écrit par Bastien 

Par le passé, j’ai eu à travailler sur un projet collaboratif dans lequel aucun outil de versionning de base de données n’avait été mis en place.

Arrivé à un certain degré de maturité sur ce projet, les spécifications fonctionnelles ont été revues et il a fallu faire de grosses modifications dans nos schémas de bases.

Sans surprise : cette refonte du Modèle Conceptuel de Donnée a été catastrophique. La donnée et les schémas de base des différents environnements n’étaient pas cohérents entre eux. Résultat : une partie de la donnée s’est retrouvée inutilisable et les conséquences ont été très lourdes sur ce projet.

Heureusement, il existe des solutions pour éviter ce genre de problème. Dans cet article, je vais vous présenter l’une d’entre elles, Liquibase. 

Liquibase, qu’est-ce que c’est ?

Liquibase est une bibliothèque de versionning de bases de données. Elle permet de suivre, de gérer et d’appliquer des changements de schéma de bases de données.

Les raisons qui peuvent nous pousser à utiliser Liquibase sont multiples. Grâce à sa puissante gestion des versions, on peut avoir un meilleur suivi de l’évolution des schémas de base au fil du temps (on a bien évidemment possibilité de monter de versions, mais également de revenir à une version antérieure, avec grâce à un système de rollback). Dans le cas d’un projet collaboratif, les développeurs s’assurent de travailler sur des modèles de bases de données identiques à chaque étape du projet.

On pourrait dire que Liquibase est (en quelque sorte) aux bases de données, ce que git est au code.

Liquibase a été lancé en 2006 et est maintenant compatible avec plus de 50 Systèmes de Gestion de Bases Données. Liquibase gère aussi bien des SGBD de type relationnels (comme Oracle, MySQL, PostgreSQL), “NoSQL” (MongoDB, Cassandra…) ou même cloud (Amazon RDS, Google Cloud SQL, Microsoft Azure SQL…). Cette prise en charge de nombreux SGBD lui assurent une grande flexibilité et une grande reproductibilité. Un grand avantage de Liquibase est qu’il permet de gérer facilement la migration d’une base de donnée à une autre (voir la partie Fonctionnement, un peu plus bas dans l’article).

Dans la suite de cet article, je vais montrer, un petit exemple purement pédagogique d’utilisation. Mon but n’est évidemment pas de remplacer la doc technique officielle, mais simplement de donner un aperçu de quelques possibilités qu’offre Liquibase.

Intégration de Liquibase

  • Je commence par créer une base de donnée sur mon poste local
$ mysql > CREATE DATABASE liquibase_sample_database;
  • Dans mon IDE, je crée un nouveau projet, je choisis Maven comme Build system
  • J’édite mon fichier pom.xml de façon à ajouter la dépendance et le plugin liquibase
<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
    <modelVersion>4.0.0</modelVersion>  
  
    <groupId>org.example</groupId>  
    <artifactId>liquibase-sample</artifactId>  
    <version>1.0-SNAPSHOT</version>  
  
    <properties>  
        <maven.compiler.source>11</maven.compiler.source>  
        <maven.compiler.target>11</maven.compiler.target>  
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
    </properties>  
  
    <dependencies>  
        <!--Dépendance liquibase-->  
        <dependency>  
            <groupId>org.liquibase</groupId>  
            <artifactId>liquibase-core</artifactId>  
            <version>4.19.0</version>  
        </dependency>  
    </dependencies>  
  
    <build>  
        <plugins>  
            <!--Plugin liquibase-->  
            <plugin>  
                <groupId>org.liquibase</groupId>  
                <artifactId>liquibase-maven-plugin</artifactId>  
                <version>4.19.0</version>  
                <configuration>  
                    <!-- Chemin vers le fichier de propriété à créer-->  
                    <propertyFile>src/main/resources/liquibase.properties</propertyFile>  
                </configuration>  
                <dependencies>  
                    <dependency>  
                        <groupId>com.microsoft.sqlserver</groupId>  
                        <artifactId>mssql-jdbc</artifactId>  
                        <version>9.4.1.jre8</version>  
                    </dependency>  
                </dependencies>  
            </plugin>  
        </plugins>  
    </build>  
  
</project>
  • Je crée un fichier de propriétés au niveau d’arborescence décrit dans mon pom.xml et j’ajoute le contenu suivant :
driver=com.mysql.cj.jdbc.Driver # Ici mysql, mais le choix de SGBD est vaste   
url=jdbc:mysql://localhost:3306/liquibase\_sample\_database  
username=YOUR_USERNAME  
password=YOUR_PASSWORD  
  
# "changeLogFile" correspond au chemin de mon point d'entrée pour les   
# modifications à apporter en base de donnée.  
changeLogFile=1.0.0/db-changelog.xml 
  • Un mvn install et le tour est joué !

Fonctionnement

Notion de ChangeSet

Le fonctionnement de Liquibase repose sur les changeSet. Ce sont des fichiers markup (xml, yaml, json…) qui décrivent les changements que l’on souhaite apporter à une base de donnée.

Par changement on entend des actions qui peuvent être la création, la modification ou la suppression de tables, de colonnes, de contraintes référentielles, de données. En bref, un peu toutes les opérations que l’on peut-être amené à manipuler en travaillant dans une base de donnée.

L’utilisation de ces formats de fichiers balisés aide à l’automatisation, puisque c’est Liquibase qui gère la jonction entre ces derniers, et les langages propres aux SGBD. Pas besoin d’écrire des requêtes compliquées et propres à chaque SGBD.

Voici un exemple de changeSet, la syntaxe est très simple :

<?xml version="1.0" encoding="utf-8" ?>  
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"  
                   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.1.xsd">  
  
      
    <!-- Un changeSet est défini par un identifiant "id" (unique dans le projet)  
    et un "author". -->  
    <changeSet id="1" author="bmatthai">  
          
        <!-- Je définie ici une précondition pour éviter les conflits.   
        Si la table "car" existe déjà, je sette la valeur MARK\_RAN -->  
        <preConditions onFail="MARK\_RAN">  
            <not>  
                <tableExists tableName="car"/>  
            </not>  
        </preConditions>  
  
        <!-- Je crée une table "car" dans laquelle j'ajoute des champs id et   
        model -->  
        <createTable tableName="car">  
            <column name="id" type="BIGINT" autoIncrement="true">  
                <constraints primaryKey="true" nullable="false"/>  
            </column>  
            <column name="model" type="VARCHAR(255)" defaultValue="none">  
                <constraints nullable="false"/>  
            </column>  
  
        </createTable>  
  
    </changeSet>  
  
</databaseChangeLog>

Dans mon exemple minimaliste ci-dessus, j’ai défini deux champs id et model dans ma table Car. Je leur ai également fourni des contraintes (nullabilité et clé primaire). Toutefois, une bonne pratique peut être de séparer les fichiers de changeSet contenant les schémas de base de donnée, ceux contenant les contraintes complexes (nullabilité, valeurs par défaut, clés étrangères, unicité…), et ceux contenant de la modification de donnée. En procédant ainsi il est plus simple de trouver rapidement un changeSet en particulier, et ainsi de mieux gérer les éventuelles erreurs de déploiement.

Les changements dans la base de données sont appliqués dans l’ordre séquentiel dans lequel ils sont définis dans le changeLogFile (comme décrit ci-dessus dans la partie Intégration).

Logging et historisation

Une fois vos différents changeSet prêts, vous pouvez “jouer” (exécuter) votre liquibase en utilisant la commande mvn install -f pom.xml (ou en CLI avec la commande liquibase update). Attention à sélectionner le bon profil, dans le cas contraire vous pourriez appliquer prématurément vos changement sur le mauvais environnement. (En prod par exemple !)

Si tout s’est bien passé, vous devriez avoir à ce stade les tables correspondant à vos changeSet joués. Liquibase créé également deux tables annexes :

  • DATABASECHANGELOG est utilisée pour suivre les modifications apportées au schéma de la base de données, permettant ainsi de garder une trace de l’historique des modifications et de garantir l’intégrité de la structure de la base de données.
  • DATABASECHANGELOGLOCK permet d’éviter les accès concurrents et donc de garder une cohérence dans la base.

La table DATABASECHANGELOG contient notamment un champ MD5SUM qui correspond au “hash” d’un changeSet. Ainsi on conserve l’historique des changeSet qui ont déjà été joué. Modifier un changeSet déjà joué est une mauvaise pratique qui peut entraîner des incohérences dans la base de donnée. La bonne façon de faire est de créer un nouveau changeSet qui annule ou modifie l’existant.

Aperçu de la table DATABASECHANGELOG après avoir joué mon liquibase

Quelques notions importantes

Un avantage de Liquibase est qu’il offre une grande flexibilité au niveau de la gestion des versions. Il est possible de “jongler” entre les versions et les environnements : on peut monter de version, mais il est aussi possible de revenir à une version plus ancienne de la BDD; A condition d’utiliser certaines notions, que nous allons voir ci-dessous :

Rollback

Dans un changeSet, on peut définir une ou plusieurs balises rollback, qui contient les opérations inverses à celles faites dans le changeSet.

Dans mon exemple de changeSet ci-dessus, qui consiste à créer une table Car je peux rajouter une balise rollback qui supprime tout simplement cette table.

<rollback>  
    <dropTable tableName="car"/>  
</rollback>

Note : si un changeSet opère plusieurs modifications en base, chaque modification devrait avoir un rollback correspondant.

Labels

Les labels correspondent à des identifiants de version, que l’on peut définir de façon optionnelle au niveau de la balise changeSet :

<changeSet id="1" author="bmatthai" labels="1.0">

Les labels permettent d’identifier des versions de la base de donnée. En utilisant la CLI on peut filtrer sur les labels de la façon suivante :

$ liquibase update --labels=1.0  
  
# A l'inverse on peut aussi exclure un label en particulier :  
$ liquibase update --liquibase update --excludeLabels=2.0

Attention : dans Liquibase il existe aussi une notion de tags, qui servent à enregistrer un état de BDD. Les labels, eux servent à contrôler quels changeSet seront joués lors d’une migration de BDD.

Contexte

Les contextes sont un peu similaires aux labels, mais eux servent plutôt à filtrer des changements à appliquer en fonction d’autres critères comme l’environnement.

<changeSet id="1" author="bmatthai" labels="1.0" contextFilter="local">

Comme pour les labels, on peut filtrer sur le contexte:

$ liquibase update --contexts=local  
  
# Ou bien en excluant un contexte en particulier :  
# $ liquibase update --excludeContexts=production

Conclusion

Que vous partiez d’un projet déjà existant ou commenciez un nouveau projet from scratch, je recommande vivement l’utilisation d’un outil de gestion de version tel que Liquibase pour gérer vos BDD. Bien utilisé, vous y gagnerez probablement beaucoup de temps et faciliterez grandement la collaboration entre les différentes personnes travaillant sur le projet.

En résumé

  • Liquibase est un outil de versionning de BDD compatible avec de nombreux SGBD (relationnel, non-relationnel, cloud)
  • On peut l’utiliser avec tous types d’opérations (création, modification, suppression de schéma de base, de contraintes, de données…)
  • liquibase fonctionne avec des “changeSet” (qui décrivent des changements à apporter à une BDD) dans des fichiers de balisage (markup)
  • Une fois la procédure liquibase exécutée, on ne touche plus aux changeSet. Si on veut faire machine arrière, on crée un nouveau changeSet qui annule les coquilles existantes
  • Les tables DATABASECHANGLOG et DATABASECHANGELOGLOCK permettent de garantir la cohérence des tables
  • Les notions de labels et de contexte permettent de définir, de filtrer sur des versions spécifiques de BDD ou d’environnement

À lire aussi

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique

Lire la suite

intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 

Lire la suite

Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 

Lire la suite

image miniature les nouveautés Atlassian
26 février 2025

Les nouveautés Atlassian en 2025

Lire la suite

Articles associés

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique


Lire la suite
intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 


Lire la suite
Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 


Lire la suite

À propos

  • Qui sommes-nous ?
  • Références
  • RSE
  • Ressources

Offres

  • Applications métier
  • Collaboration des équipes
  • Sécurisation et optimisation du système d’information
  • Transformation numérique

Expertises

  • Développement logiciel
  • DevSecOps
  • Intégration de logiciels et négoce de licences
  • Logiciel de CRM et de gestion
  • UX/UI design
  • Accessibilité Numérique
  • Démarches simplifiées
  • Formations Atlassian

Carrières

  • Pourquoi rejoindre Ouidou ?
  • Nous rejoindre
  • Rencontrer nos collaborateurs
  • Grandir chez Ouidou

SIEGE SOCIAL
70-74 boulevard Garibaldi, 75015 Paris

Ouidou Nord
165 Avenue de Bretagne, 59000 Lille

Ouidou Rhône-Alpes
4 place Amédée Bonnet, 69002 Lyon

Ouidou Grand-Ouest
2 rue Crucy, 44000 Nantes

Ouidou Grand-Est
7 cour des Cigarières, 67000 Strasbourg

  • Linkedin Ouidou
  • GitHub Ouidou
  • Youtube Ouidou
© 2024 Ouidou | Tous droits réservés | Plan du site | Mentions légales | Déclaration d'accessibilité
    Nous contacter