Migrations de bases de données avec Flyway

1. Introduction

Cet article décrit les concepts clés de Flyway et comment nous pouvons utiliser ce framework pour remodeler en continu le schéma de base de données de notre application de manière fiable et simple. À la fin, nous présenterons un exemple de gestion d'une base de données H2 en mémoire à l'aide d'un plugin Maven Flyway.

Flyway met à jour une base de données d'une version à une autre à l'aide de migrations. Nous pouvons écrire des migrations soit en SQL avec une syntaxe spécifique à la base de données, soit en Java pour des transformations de base de données avancées.

Les migrations peuvent être versionnées ou répétables. Le premier a une version unique et est appliqué exactement une fois. Ce dernier n'a pas de version. Au lieu de cela, ils sont (ré) appliqués chaque fois que leur somme de contrôle change.

Au cours d'une seule exécution de migration, les migrations répétables sont toujours appliquées en dernier, une fois que les migrations versionnées en attente ont été exécutées. Les migrations répétables sont appliquées dans l'ordre de leur description. Pour une seule migration, toutes les instructions sont exécutées dans une seule transaction de base de données.

Dans cet article, nous nous concentrons principalement sur la façon dont nous pouvons utiliser le plugin Maven pour effectuer des migrations de bases de données.

2. Plugin Flyway Maven

Pour installer un plugin Flyway Maven, ajoutons la définition de plugin suivante à notre pom.xml:

 org.flywaydb flyway-maven-plugin 4.0.3 

Nous pouvons vérifier la dernière version du plugin disponible sur Maven Central.

Ce plugin Maven peut être configuré de quatre manières différentes. Veuillez vous référer à la documentation pour obtenir une liste de toutes les propriétés configurables.

2.1. Configuration du plugin

Nous pouvons configurer le plugin directement via le tag dans la définition du plugin de notre pom.xml:

 org.flywaydb flyway-maven-plugin 4.0.3  databaseUser databasePassword  schemaName  ...  

2.2. Propriétés Maven

Nous pouvons également configurer le plugin en spécifiant des propriétés configurables comme propriétés Maven dans notre pom:

 ...  databaseUser databasePassword schemaName ...  ... 

2.3. Fichier de configuration externe

Nous pouvons également fournir la configuration du plugin dans un fichier .properties séparé :

flyway.user=databaseUser flyway.password=databasePassword flyway.schemas=schemaName ...

Le nom du fichier de configuration par défaut est flyway.properties et doit résider dans le même répertoire que le fichier pom.xml . Le codage est spécifié par flyway.encoding (la valeur par défaut est UTF-8 ).

Si vous utilisez un autre nom (par exemple customConfig.properties ) comme fichier de configuration, il doit être spécifié explicitement lors de l'appel de la commande Maven:

$ mvn -Dflyway.configFile=customConfig.properties

2.4. Propriétés du système

Enfin, toutes les propriétés de configuration peuvent également être spécifiées en tant que propriétés système lors de l'appel de Maven sur la ligne de commande:

$ mvn -Dflyway.user=databaseUser -Dflyway.password=databasePassword -Dflyway.schemas=schemaName

Voici un ordre de priorité lorsqu'une configuration est spécifiée de plusieurs manières:

  1. Propriétés du système
  2. Fichier de configuration externe
  3. Propriétés de Maven
  4. Configuration du plugin

3. Exemple de migration

Dans cette section, nous parcourons les étapes requises pour migrer un schéma de base de données vers une base de données H2 en mémoire à l'aide du plugin Maven. Nous utilisons un fichier externe pour configurer Flyway.

3.1. Mettre à jour le POM

Tout d'abord, ajoutons H2 comme dépendance:

 com.h2database h2 1.4.196 

Nous pouvons, encore une fois, vérifier la dernière version du pilote disponible sur Maven Central. Nous ajouterions également le plugin Flyway comme expliqué précédemment.

3.2. Configurer Flyway à l'aide d'un fichier externe

Ensuite, nous créons myFlywayConfig.properties dans $ PROJECT_ROOT avec le contenu suivant:

flyway.user=databaseUser flyway.password=databasePassword flyway.schemas=app-db flyway.url=jdbc:h2:mem:DATABASE flyway.locations=filesystem:db/migration

La configuration ci-dessus spécifie que nos scripts de migration se trouvent dans le répertoire db / migration . Il se connecte à une instance H2 en mémoire à l'aide de databaseUser et databasePassword .

Le schéma de base de données d' application est app-db .

Bien sûr, nous remplaçons flyway.user, flyway.password et flyway.url par notre propre nom d'utilisateur de base de données, mot de passe de base de données et URL de base de données de manière appropriée.

3.3. Définir la première migration

Flyway adhère à la convention de dénomination suivante pour les scripts de migration:

__. sql

Où:

  • – Default prefix is V, which may be configured in the above configuration file using the flyway.sqlMigrationPrefix property.
  • – Migration version number. Major and minor versions may be separated by an underscore. The migration version should always start with 1.
  • – Textual description of the migration. The description needs to be separated from the version numbers with a double underscore.

Example: V1_1_0__my_first_migration.sql

So, let's create a directory db/migration in $PROJECT_ROOT with a migration script named V1_0__create_employee_schema.sql containing SQL instructions to create the employee table:

CREATE TABLE IF NOT EXISTS `employee` ( `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(20), `email` varchar(50), `date_of_birth` timestamp )ENGINE=InnoDB DEFAULT CHARSET=UTF8;

3.4. Execute Migrations

Next, we invoke the following Maven command from $PROJECT_ROOT to execute database migrations:

$ mvn clean flyway:migrate -Dflyway.configFile=myFlywayConfig.properties

This should result in our first successful migration.

The database schema should now be depicted as follows:

employee: +----+------+-------+---------------+ | id | name | email | date_of_birth | +----+------+-------+---------------+

We can repeat definition and execution steps to do more migrations.

3.5. Define and Execute Second Migration

Let's see what a second migration looks like by creating a second migration file with name V2_0_create_department_schema.sql containing the following two queries:

CREATE TABLE IF NOT EXISTS `department` ( `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(20) )ENGINE=InnoDB DEFAULT CHARSET=UTF8; ALTER TABLE `employee` ADD `dept_id` int AFTER `email`;

We'll execute a similar migration like we did the first time.

And now, our database schema has changed to add a new column to employee and a new table:

employee: +----+------+-------+---------+---------------+ | id | name | email | dept_id | date_of_birth | +----+------+-------+---------+---------------+
department: +----+------+ | id | name | +----+------+

We may now verify that both migrations were indeed successful by invoking the following Maven command:

$ mvn flyway:info -Dflyway.configFile=myFlywayConfig.properties

4. Disabling Flyway in Spring Boot

Sometimes we may need to disable Flyway migrations under certain circumstances.

For example, it's a common practice to generate database schema based on the entities during tests. In such a situation, we can disable Flyway under the test profile.

Let's see how easy it is in Spring Boot.

4.1. Spring Boot 1.x

All we need to do is to set the flyway.enabled property in our application-test.properties file:

flyway.enabled=false

4.2. Spring Boot 2.x

In the more recent versions of Spring Boot, this property has been changed to spring.flyway.enabled:

spring.flyway.enabled=false

4.3 Empty FlywayMigrationStrategy

If we only want to disable automatic Flyway migration on startup, but still be able to trigger the migration manually, then using the properties described above isn't a good choice.

That's because in such a situation Spring Boot will not auto-configure the Flyway bean anymore. Consequently, we'd have to provide it on our own which isn't very convenient.

So if this is our use case, we can leave Flyway enabled and implement an empty FlywayMigrationStrategy:

@Configuration public class EmptyMigrationStrategyConfig { @Bean public FlywayMigrationStrategy flywayMigrationStrategy() { return flyway -> { // do nothing }; } }

This will effectively disable Flyway migration on application startup.

But we'll still be able to trigger the migration manually:

@RunWith(SpringRunner.class) @SpringBootTest public class ManualFlywayMigrationIntegrationTest { @Autowired private Flyway flyway; @Test public void skipAutomaticAndTriggerManualFlywayMigration() { flyway.migrate(); } }

5. How Flyway Works

To keep track of which migrations have already been applied, when and by whom, it adds a special bookkeeping table to your schema. This metadata table also tracks migration checksums and whether or not the migrations were successful.

The framework performs the following steps to accommodate evolving database schemas:

  1. It checks a database schema to locate its metadata table (SCHEMA_VERSION by default). If the metadata table does not exist, it will create one
  2. It scans an application classpath for available migrations
  3. It compares migrations against the metadata table. If a version number is lower or equal to a version marked as current, it is ignored
  4. It marks any remaining migrations as pending migrations. These are sorted based on version number and are executed in order
  5. As each migration is applied, the metadata table is updated accordingly

6. Commands

Flyway supports the following basic commands to manage database migrations.

  • Info: Prints current status/version of a database schema. It prints which migrations are pending, which migrations have been applied, what is the status of applied migrations and when they were applied.
  • Migrate: Migrates a database schema to the current version. It scans the classpath for available migrations and applies pending migrations.
  • Baseline: Baselines an existing database, excluding all migrations, including baselineVersion. Baseline helps to start with Flyway in an existing database. Newer migrations can then be applied normally.
  • Valider : valide le schéma de base de données actuel par rapport aux migrations disponibles.
  • Réparation : table de métadonnées des réparations.
  • Nettoyer : supprime tous les objets dans un schéma configuré. Tous les objets de base de données sont supprimés. Bien sûr, vous ne devez jamais utiliser clean sur une base de données de production.

7. Conclusion

Dans cet article, nous avons montré comment Flyway fonctionne et comment nous pouvons utiliser ce framework pour remodeler de manière fiable notre base de données d'applications.

Le code accompagnant cet article est disponible sur GitHub.