Introduction of Flyway with Spring Boot
Flyway is the Apache v2 licensed open-source tool that makes database migrations easy. You can think of Flyway as version control for your database. It lets you evolve your database schema easily and reliably across all your instances.
Some of its features included:
- Smooth database migration
- Version control
- Rollback machanism
- Callbacks (Java callback and SQL callback)
1. Installation
Add the Flyway dependency to your pom.xml
or build.gradle
if you're using Gradle instead of Maven.
Maven:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>6.4.3</version>
</dependency>
Gradle:
implementation 'org.flywaydb:flyway-core:6.4.3
Optionally, if you want to use Flyway with command line eg. mvn flyway:info
/ ./gradlew flywayInfo
, add the following plugin as well.
Maven:
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>6.4.3</version>
</plugin>
Gradle:
plugins {
id "org.flywaydb.flyway" version "6.4.3"
}
Here are some of the common commands you could use. Also see here for the full list.
Maven | Gradle | Description |
---|---|---|
migrate | flywayMigrate | Migrates the database |
clean | flywayClean | Drops all objects in the configured schemas |
info | flywayInfo | Prints the details and status information about all the migrations |
2. Configuration
Flyway works out of the box if you integrate it from the beginning of the project. However, if you plan to integrate to the existing database you can do so as well, just require a little configuration. See Section 2.1
2.1 Enable baseline-on-migration
Note: For existing database only
In your application.yml, set baseline-on-migration
to true
spring:
flyway:
enabled: true
baseline-on-migrate: true
Note that you only need to set this the first time. Subsequent migration you can choose to turn it off.
Also, for existing database, you cannot start the Flyway migration version from V1
. Name your migration from anything higher than V1
onwards, such as V1_0_1
2.2 Create a migration file
Flyway reads the migration script files by default from your src/main/resources/db/migration
directory.
── db
└── migration
└── V1_0_0__create_users.sql
The migration file has its own naming convention that MUST BE STRICTLY FOLLOWED.
The migration file format = <Prefix><Version>__<Description>.sql
where prefix is V
typically followed by version number which is separated by underscore _
or a dot .
. After double underscores __
is the description of your choice also separated words by underscore.
Inside the migration file contains the pure SQL statements. For example:
CREATE TABLE IF NOT EXISTS `users` (
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(255),
password VARCHAR(255),
email VARCHAR(255),
role VARCHAR(255),
PRIMARY KEY (id)
);
After running the application, you should see something like this in the console.
3 Callbacks
Flyway emits certain events during the migration process that you can hook into. Refer here for all possible callback events.
Practically, what you usually need is afterEachMigrate
event, which runs after each successful migration.
There are 2 types of Callback: SQL Callback and Java Callback
3.1 SQL Callback
This is the simplest form of callback you could use. All you have to do is to create a .sql
file of certain naming convention. For example: beforeMigrate.sql
, afterMigrate.sql
, and Flyway will automatically execute it during the migration process.
By default, Flyway will search for these files in the src/main/resources/db/migration
directory. You can however customize the location with Flyway's properties. Let's do this.
3.1.1 Define the callback location in application.yml
spring:
flyway:
locations:
- classpath:db/migration
- classpath:db/callback # for sql callback scripts
3.1.2 Create a directory db/callback
for callback scripts
── db
└── migration
└── callback
└── beforeMigrate.sql
└── afterMigrate.sql
-- Example of afterMigrate.sql
SELECT * FROM `users`
After running, you will see the callback output in the console:
You can refer here for the full list of callback events.
3.2 Java Callback
Java callback is the most flexible way to perform custom business logic after migration. You can even have different callback based on a specific migration version.
Example:
@Component
public class MyFlywayCallback implements Callback {
private UserRepository userRepository;
public MyFlywayCallback(@Lazy UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean supports(Event event, Context context) {
// telling Flyway to only trigger callback for these events
return event.equals(Event.BEFORE_EACH_MIGRATE) || event.equals(Event.AFTER_EACH_MIGRATE);
}
@Override
public boolean canHandleInTransaction(Event event, Context context) {
return false;
}
@Override
public void handle(Event event, Context context) {
switch (event) {
case BEFORE_EACH_MIGRATE:
// Some logic before the migration begins...
break;
case AFTER_EACH_MIGRATE: {
MigrationInfo migration = context.getMigrationInfo();
String version = migration.getVersion().getVersion();
Faker faker = new Faker();
switch (version) {
case "1.0.0": {
// v1.0.0 migration callback logic
break;
}
case "1.0.1": {
// v1.0.1 migration callback logic
break;
}
}
}
}
}
}
It's helpful to note that Flyway will execute Java Callback first before SQL Callback.
4. Migration History
Flyway keeps track of the migrations in its own table flyway_schema_history
. This provides you the overview of the migration history and the status of each migration.
Conclusion
This is just tip of the Flyway iceberg. If you are interested in the more advanced features, feel free to take a look at the official documentation.
Have fun!
Check out the demo project on Github.