-
Notifications
You must be signed in to change notification settings - Fork 7
Implement Flyway for database migrations #130
Description
Problem
The project currently lacks a structured approach to database schema versioning and migrations. This leads to:
- Manual SQL script execution for schema changes
- Inconsistent database states across environments (dev, test, prod)
- Difficulty tracking which migrations have been applied
- Risk of human error when deploying schema changes
- No rollback strategy for failed migrations
- Challenges onboarding new developers who need to set up local databases
Without a proper migration tool, database evolution becomes error-prone and difficult to manage as the application grows.
Required by: #286 (Add PostgreSQL support with unified migration-based initialization)
Proposed Solution
Integrate Flyway as the database migration tool for the Spring Boot project. This will:
- Provide version control for database schemas
- Enable automated, repeatable migrations across all environments
- Track migration history in the database
- Integrate seamlessly with Spring Boot auto-configuration
- Allow easy rollback and repair of failed migrations
- Ensure consistency between application code and database schema
- Lay the groundwork for PostgreSQL support (Add PostgreSQL support with unified migration-based initialization #286) — migrations must use SQL compatible with both SQLite and PostgreSQL
Suggested Approach
1. Add Flyway dependencies
Update pom.xml:
<!-- Flyway Core -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<!-- Flyway Database PostgreSQL (required for PostgreSQL support in Flyway 10+) -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>2. Configure Flyway in Spring Boot
Update application.properties:
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.jpa.hibernate.ddl-auto=validateRemove
spring.datasource.initialization-mode,schema.sql, anddata.sqlif present — Flyway takes over all schema management.
3. Create migration directory structure
src/main/resources/
└── db/
└── migration/
├── V1__Create_players_table.sql
├── V2__Seed_starting11.sql
└── V3__Seed_substitutes.sql
Educational note: Splitting seed data across two migrations illustrates the incremental, composable nature of the migration system. Rolling back
V3removes only the substitutes, leaving the starting 11 intact.
4. Migration naming convention
Follow Flyway's versioned migration pattern:
V{version}__{description}.sql
Examples:
V1__Create_players_table.sqlV2__Seed_starting11.sqlV3__Seed_substitutes.sql
5. Write cross-dialect compatible SQL
Migrations must work with both SQLite (local dev/test) and PostgreSQL (Docker/production, see #286). Avoid provider-specific syntax:
| Avoid (SQLite-only) | Avoid (PostgreSQL-only) | Use instead |
|---|---|---|
AUTOINCREMENT |
SERIAL / BIGSERIAL |
INTEGER PRIMARY KEY (SQLite auto-assigns; use identity columns in PG via Hibernate) |
TEXT for all strings |
VARCHAR(n) enforced |
VARCHAR(n) works in both |
INTEGER for booleans |
BOOLEAN |
INTEGER (Hibernate maps it correctly for both) |
Hibernate/JPA with ddl-auto=validate will handle the ORM layer; Flyway handles the DDL. Keep migration SQL as standard as possible.
V1__Create_players_table.sql (example):
CREATE TABLE IF NOT EXISTS players (
id INTEGER PRIMARY KEY,
firstName VARCHAR(100),
middleName VARCHAR(100),
lastName VARCHAR(100),
dateOfBirth VARCHAR(20),
squadNumber INTEGER,
position VARCHAR(50),
abbrPosition VARCHAR(10),
team VARCHAR(100),
league VARCHAR(100),
starting11 INTEGER
);V2__Seed_starting11.sql (example):
INSERT INTO players (firstName, middleName, lastName, dateOfBirth, squadNumber, position, abbrPosition, team, league, starting11)
VALUES
('Emiliano', 'Viviano', 'Martínez', '1992-08-02', 23, 'Goalkeeper', 'GK', 'Aston Villa', 'Premier League', 1),
-- ... 10 more Starting XI players (starting11 = 1)
;V3__Seed_substitutes.sql (example):
INSERT INTO players (firstName, middleName, lastName, dateOfBirth, squadNumber, position, abbrPosition, team, league, starting11)
VALUES
('Gerónimo', NULL, 'Rulli', '1992-05-07', 12, 'Goalkeeper', 'GK', 'Marseille', 'Ligue 1', 0),
-- ... 13 more Substitute players (starting11 = 0)
;6. Update database initialization logic
- Remove any manual
schema.sql/data.sqlfiles - Remove
spring.sql.init.*properties - Let Flyway handle all schema and seed data management
7. Update documentation
README.md:
- Document migration workflow (how to create and apply new migrations)
- Explain that the database auto-initializes via Flyway on startup
- Add database reset workflow: delete the
.dbfile and re-run the app
Acceptance Criteria
-
flyway-coreandflyway-database-postgresqladded topom.xml - Flyway configured in
application.properties(spring.flyway.enabled=true) -
spring.jpa.hibernate.ddl-auto=validate(Flyway owns DDL, not Hibernate) - Migration directory created at
src/main/resources/db/migration/ -
V1__Create_players_table.sqlcreated with cross-dialect compatible SQL -
V2__Seed_starting11.sqlseeds the 11 Starting XI players (starting11 = 1) -
V3__Seed_substitutes.sqlseeds the 14 Substitute players (starting11 = 0) - Rolling back
V3removes only substitutes;V2removes only Starting XI - Application starts successfully and Flyway applies migrations automatically
-
flyway_schema_historytable is created and populated correctly - Manual
schema.sql/data.sqlfiles removed (if present) - All existing tests pass
- Application can start from a clean database and build schema via migrations
- Migration SQL is verified to be compatible with both SQLite and PostgreSQL
- README.md updated with migration workflow
References
- Flyway Official Documentation
- Spring Boot Flyway Integration
- Flyway Naming Patterns
- PostgreSQL Docker Official Images
- Required by: Add PostgreSQL support with unified migration-based initialization #286 (Add PostgreSQL support with unified migration-based initialization)