Accueil Nos publications Blog Mettez de l’agilité dans vos bases de données avec Flyway

Mettez de l’agilité dans vos bases de données avec Flyway

flyway_logo

Trouver un bon outil de versionning ou de migration de base de données peut vous aider à gagner énormément en temps et en qualité. Il existe des outils comme Rails db RakeLiquibase ou dbdeploy, qui nécessitent parfois une DSL spécifique. Mais en environnement Java, Flyway se distingue par une facilité d’utilisation et une intégration optimale.

Vous ne trouverez pas de comparatif dans cet article : ce n’est pas l’objet ! Mais je signale au passage que vous pouvez en trouver un très bon sur le site de Flyway (ici). Dans cet article, je vais plutôt vous présenter, via différents exemples et cas d’utilisations* pratiques,  l’outil que vous pourrez facilement adapter et utiliser dans vos projets.

*Vous pouvez télécharger tous les projets qui correspondent aux exemples ici.

Un outil de versionning pour les bases de données ?

L’intérêt des outils de gestion de versions, tels que Git ou SVN, n’est plus à prouver. De la même manière, Flyway vient répondre à ce besoin pour les bases de données.

Il arrive souvent que toutes les évolutions de la base de données passent par un script SQL, joué manuellement. Mais dans une grande équipe, garder sa base locale à jour devient rapidement très compliqué.  Du coup, vous perdez un temps précieux à débuguer pour vous rendre compte au final qu’il manque une colonne sur une table, ajoutée le jour précédent par un collègue. Cette mise jour de base de données doit donc se faire manuellement en local.

Rassurez-vous, avec Flyway tout cela est fini : il automatise totalement cette tâche, et plus encore.

Comment ça fonctionne ?

Flyway repose sur une table de métadonnées qui permet de savoir dans quel état se trouve la base. Cette table est créée automatiquement à la première exécution du logiciel. Ensuite, les détails sont stockés dans celle-ci chaque fois que la migration est appliquée. Flyway peut alors connaître la version actuelle du schéma, ainsi que les migrations qui ont été faites, et si la dernière a réussi ou échoué.

Chacune d’entre elles se présente sous forme de script, avec une version associée. Au lancement de Flyway, tous les scripts sont vérifiés : s’il en trouve un nouveau, ajouté par votre collègue via SVN , il l’exécute pour vous. Au final, et c’est le plus intéressant, tout est transparent pour vous! Des explications plus détaillées, avec des schémas, se trouvent sur le site de Flyway ici.

En pratique comment ça marche ?

Flyway peut s’intégrer facilement à votre application, cela via Spring, Maven, Ant, ou même en ligne de commande. Voyons d’abord ce que c’est un script de migrations.

Scripts de migration

Ils peuvent être écrits en SQL ou en Java. Chaque script représente une version unique. L’ensemble de scripts doivent se trouver dans le classpath, dans un package qui s’appelle « db.migration » (ce peut être modifié). Pour reconnaître ces scripts, Flyway utilise une convention de nommage spécifique : ils commencent par la lettre « V », suivie de la version (chiffre ou lettre), séparée par des « _ » ou des points. On peut ajouter la description du script si on le souhaite.

Ex : V1_ajout_nouvelleColonne.sql

La plupart du temps, on utilisera des fichiers SQL pour la migration. Pour d’autres cas plus compliqués, on peut se servir directement de Java (pour des LOBs par exemple, ou pour le besoin de transformer les données avant insertion).

Migration en ligne de commande

Flyway peut être utilisé simplement en ligne de commande :

  • Commencez par le télécharger ici.
  • Ajoutez le connecteur qui correspond à votre base de données dans le répertoire “jar” se trouvant dans le dossier “flyway” téléchargé
  • Configurez l’accès à la base dans le fichier “flyway.properties” qui figure dans le même dossier “flyway”.
  • Mettez vos scripts de migration dans le répertoire “sql” du même dossier

La configuration est maintenant terminée. Pour effectuer la migration, tapez ceci pour l’initialisation :

"> flyway init"

A cette étape, Flyway va créer la table “schema_version”. Ensuite tapez la commande suivante dès lors que vous ajoutez un nouveau script :

<

pre>”>  flyway migrate”


C:\Users\rabii\Downloads\flyway-commandline-2.0.3-dist\flyway-commandline-2.0.3>flyway init
Flyway (Command-line Tool) v.2.0.3

Creating Metadata table: `base_test_4`.`schema_version`
Schema initialized with version: 0

C:\Users\rabii\Downloads\flyway-commandline-2.0.3-dist\flyway-commandline-2.0.3>flyway migrate
Flyway (Command-line Tool) v.2.0.3

Current schema version: 0
Migrating to version 1.0.0
Migrating to version 1.1.0
Migrating to version 2.0.0
Migrating to version 2.1.0
Successfully applied 4 migrations (execution time 00:00.259s).

C:\Users\rabii\Downloads\flyway-commandline-2.0.3-dist\flyway-commandline-2.0.3>

Si vous vérifiez votre base de données, vous trouverez que Flyway a correctement exécuté vos scripts SQL, et que la table “schema_version” contient désormais une entrée pour chacun de vos scripts avec nom, date d’exécution et statut :

schema_version

Migration via Maven

Vous pouvez aussi effectuer les migrations via Maven. Un plugin est fourni, on peut l’ajouter simplement à notre pom :



<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.soat</groupId>
<artifactId>flyway-sample-mvn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.test.failure.ignore>true</maven.test.failure.ignore>
<spring.framework.version>3.0.5.RELEASE</spring.framework.version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>com.googlecode.flyway</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>1.6.1</version>
<configuration>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost:3306/base_test_2</url>
<user>root</user>
<password>chocolat</password>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.googlecode.flyway</groupId>
<artifactId>flyway-core</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
</project>

Votre projet doit ressembler à ceci :

project_mvn

Pour effectuer une migration :



C:\workspace_19_02_2012\flyway-sample-mvn>mvn flyway:init
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Unnamed - com.soat:flyway-sample-mvn:jar:0.0.1-SNAPSHOT
[INFO]    task-segment: [flyway:init]
[INFO] ------------------------------------------------------------------------
[INFO] [flyway:init {execution: default-cli}]
[INFO] Metadata table created: schema_version (Schema: base_test_2)
[INFO] Schema initialized with version: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6 seconds
[INFO] Finished at: Sun Jan 20 13:53:15 CET 2013
[INFO] Final Memory: 12M/28M
[INFO] ------------------------------------------------------------------------
C:\workspace_19_02_2012\flyway-sample-mvn>mvn flyway:migrate
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Unnamed - com.soat:flyway-sample-mvn:jar:0.0.1-SNAPSHOT
[INFO]    task-segment: [flyway:migrate]
[INFO] ------------------------------------------------------------------------
[INFO] [flyway:migrate {execution: default-cli}]
[INFO] Current schema version: 0
[INFO] Migrating to version 1.0.0
[INFO] Migrating to version 1.1.0
[INFO] Migrating to version 2.0.0
[INFO] Migrating to version 2.1.0
[INFO] Successfully applied 4 migrations (execution time 00:00.133s).
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Sun Jan 20 13:53:28 CET 2013
[INFO] Final Memory: 12M/28M
[INFO] ------------------------------------------------------------------------

Migration via Java

Il est possible de faire la migration en Java. Voici un exemple de test pour effectuer cela :



package fr.soat.lab.flyway;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.googlecode.flyway.core.Flyway;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "test-context.xml")
public class TestFlywayMigration {

@Autowired
private DataSource dataSource;

@Test
public void authorTableShouldExist() throws SQLException {

Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.migrate();
flyway.status();
}
}
 

Avant d’exécuter le test, il faut mettre mettre à jour le fichier “test-context.xml” avec vos propres données de connexion :



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context"
xmlns:tx="https://www.springframework.org/schema/tx"
xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-2.5.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-3.0.xsd">
<tx:annotation-driven />
<context:component-scan base-package="fr.soat.lab.flyway" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/base_test_3" />
<property name="username" value="root" />
<property name="password" value="chocolat" />
</bean>
</beans>

Migration via Spring

Intégrons maintenant Flyway avec Spring. Pour cela, il faut déclarer le bean Flyway avec “migrate” comme méthode d’initialisation :


...
<bean id="flyway" init-method="migrate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans

On ajoute le test TestFlywaySpring.java :

[java]
package fr.soat.lab.flyway;

import java.util.ArrayList;
import javax.sql.DataSource;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import fr.soat.lab.flyway.data.Client;
import fr.soat.lab.flyway.data.ClientDAO;
import fr.soat.lab.flyway.data.ClientDAOImpl;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = “test-context.xml”)
public class TestFlywaySpring {
@Autowired
private DataSource dataSource;

@Test
public void test() {
assert (dataSource != null);

ClientDAO clientDAO = new ClientDAOImpl();
ArrayList clients = clientDAO.getAllClients();

Assert.assertNotNull(clients);
}
}
[/java]

L’annotation @ContextConfiguration(locations = “test-context.xml”) est utilisée pour charger le contexte Spring une fois que votre test est lancé. On constate qu’au chargement de la configuration Spring, Flyway va mettre à jour automatiquement votre base de données, sans aucune commande à taper. Ainsi, à chaque déploiement de votre application, vous serez sûrs que votre base est à jour.

Conclusion

Flyway est un outil simple, pratique et facile à mettre en place. Et d’autant plus si votre équipe utilise une méthode agile, comme c’est le cas dans la mienne, et que votre base de données subit des évolutions régulières à chaque Sprint : Flyway peut donc se révéler très utile.

Plus d’informations et documentation sur le site officiel de flyway