Datenbankmigrationen mit Flyway

1. Einleitung

Dieser Artikel beschreibt die wichtigsten Konzepte von Flyway und wie wir dieses Framework verwenden können, um das Datenbankschema unserer Anwendung zuverlässig und einfach kontinuierlich umzugestalten. Am Ende präsentieren wir ein Beispiel für die Verwaltung einer speicherinternen H2-Datenbank mit einem Maven Flyway-Plugin.

Flyway aktualisiert eine Datenbank mithilfe von Migrationen von einer Version zur nächsten. Wir können Migrationen entweder in SQL mit datenbankspezifischer Syntax oder in Java für erweiterte Datenbanktransformationen schreiben.

Migrationen können entweder versioniert oder wiederholbar sein. Ersteres hat eine einzigartige Version und wird genau einmal angewendet. Letzteres hat keine Version. Stattdessen werden sie jedes Mal (erneut) angewendet, wenn sich ihre Prüfsumme ändert.

Innerhalb eines einzelnen Migrationslaufs werden wiederholbare Migrationen immer zuletzt angewendet, nachdem ausstehende versionierte Migrationen ausgeführt wurden. Wiederholbare Migrationen werden in der Reihenfolge ihrer Beschreibung angewendet. Bei einer einzelnen Migration werden alle Anweisungen innerhalb einer einzelnen Datenbanktransaktion ausgeführt.

In diesem Artikel konzentrieren wir uns hauptsächlich darauf, wie wir das Maven-Plugin verwenden können, um Datenbankmigrationen durchzuführen.

2. Flyway Maven Plugin

Um ein Flyway Maven-Plugin zu installieren, fügen wir unserer pom.xml die folgende Plugin-Definition hinzu :

 org.flywaydb flyway-maven-plugin 4.0.3 

Wir können die neueste Version des bei Maven Central verfügbaren Plugins überprüfen.

Dieses Maven-Plugin kann auf vier verschiedene Arten konfiguriert werden. In der Dokumentation finden Sie eine Liste aller konfigurierbaren Eigenschaften.

2.1. Plugin Konfiguration

Wir können das Plugin direkt über das konfigurieren Tag in der Plugin-Definition unserer pom.xml:

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

2.2. Maven Eigenschaften

Wir können das Plugin auch konfigurieren, indem wir konfigurierbare Eigenschaften als Maven- Eigenschaften in unserem POM angeben:

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

2.3. Externe Konfigurationsdatei

Wir können die Plugin-Konfiguration auch in einer separaten .properties- Datei bereitstellen :

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

Der Standardname der Konfigurationsdatei lautet flyway.properties und sollte sich im selben Verzeichnis wie die Datei pom.xml befinden . Die Codierung wird durch flyway.encoding angegeben (Standard ist UTF-8 ).

Wenn Sie einen anderen Namen (z. B. customConfig.properties ) als Konfigurationsdatei verwenden, sollte dieser beim Aufrufen des Befehls Maven explizit angegeben werden:

$ mvn -Dflyway.configFile=customConfig.properties

2.4. Systemeigenschaften

Schließlich können alle Konfigurationseigenschaften auch als Systemeigenschaften angegeben werden, wenn Maven in der Befehlszeile aufgerufen wird:

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

Es folgt eine Rangfolge, wenn eine Konfiguration auf mehrere Arten angegeben wird:

  1. Systemeigenschaften
  2. Externe Konfigurationsdatei
  3. Maven Eigenschaften
  4. Plugin Konfiguration

3. Beispiel für eine Migration

In diesem Abschnitt werden die erforderlichen Schritte zum Migrieren eines Datenbankschemas in eine speicherinterne H2-Datenbank mithilfe des Maven-Plugins beschrieben. Wir verwenden eine externe Datei, um Flyway zu konfigurieren.

3.1. POM aktualisieren

Fügen wir zunächst H2 als Abhängigkeit hinzu:

 com.h2database h2 1.4.196 

Wir können erneut die neueste Version des auf Maven Central verfügbaren Treibers überprüfen. Wir würden auch das Flyway-Plugin hinzufügen, wie zuvor erläutert.

3.2. Konfigurieren Sie Flyway mithilfe einer externen Datei

Als Nächstes erstellen wir myFlywayConfig.properties in $ PROJECT_ROOT mit folgendem Inhalt:

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

Die obige Konfiguration gibt an, dass sich unsere Migrationsskripte im Verzeichnis db / migration befinden . Es stellt mithilfe von databaseUser und databasePassword eine Verbindung zu einer speicherinternen H2-Instanz her .

Das Anwendungsdatenbankschema lautet app-db .

Natürlich ersetzen wir flyway.user, flyway.password und flyway.url entsprechend durch unseren eigenen Datenbankbenutzernamen, das Datenbankkennwort und die Datenbank-URL.

3.3. Erste Migration definieren

Flyway hält sich an die folgende Namenskonvention für Migrationsskripte:

__. sql

Wo:

  • – 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.
  • Validieren : Überprüft das aktuelle Datenbankschema anhand verfügbarer Migrationen.
  • Reparatur : Repariert die Metadatentabelle.
  • Bereinigen : Löscht alle Objekte in einem konfigurierten Schema. Alle Datenbankobjekte werden gelöscht. Natürlich sollten Sie clean in keiner Produktionsdatenbank verwenden.

7. Fazit

In diesem Artikel haben wir gezeigt, wie Flyway funktioniert und wie wir dieses Framework verwenden können, um unsere Anwendungsdatenbank zuverlässig umzugestalten.

Der diesem Artikel beigefügte Code ist auf GitHub verfügbar.