Today, I was working on an application that uses Microservices based architecture. Each Microservice had its own schema and they talk to each other using their published contracts.
We wanted to keep database migration script with each Microservice rather than keeping a common module to manage database Migrations. We might later migrate to common module for database migration but we want to start by keeping schema for each Microservice separate.
In Spring Boot services, Flyway is auto-configured with flyway-core
dependency is on the classpath.
Flyway uses flyway_schema_history
table to track the state of the database. This table is created in the default schema. Once it finds the table it scans the classpath looking for SQL or Java migration scripts. Once found it applies the migration scripts and store state in the flyway_schema_history
table as shown below.
installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | application schema init | SQL | V1__application_schema_init.sql | 311111312 | sa | 2020-06-19 12:10:57 | 158 | 1 |
This works great when you have single application/service/module responsible for applying database migration scripts.
When multiple services tries to use the default Spring Boot Flyway configuration then you will get following exception.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Validate failed:
Migration checksum mismatch for migration version 1
The above exception is because first service applied the database migration and updated the flyway_schema_history
table. When second table tries to apply the database migration it finds that both scripts checksum are different although version number is 1.
To fix this error we can specify different table names for each Microservice using the following property.
spring.flyway.table=service1_flyway_schema_history
After making the change once you run both the services you will get following exception.
org.flywaydb.core.api.FlywayException: Found non-empty schema
To solve this exception we will have to set two more properties.
spring.flyway.baseline-on-migrate=true
spring.flyway.baseline-version=0