Flyway Set-up and Integration with Spring Boot, a simple Hands-On

This article is about how to setup and integrate flyway migration tool to manage Database Schema in a Spring Boot application with simple setup. Here we use HSQL runtime database to minimize the setup and to have quick hands-on. Prerequisites: Below are the dependencies for this sample Flyway demo. Used https://start.spring.io/ to create the Spring Boot application. JDK 17 Gradle-Groovy HSQL Database Spring boot Starter Web Spring boot Starter Data JPA Lombok Flyway Migration Below is the sample Project structure. 1. Create Database Baseline/V1: Follow the below steps to integrate and test Flyway and create DB baseline. Download/Generate the Spring boot project with prerequisites mentioned above and import it to any IDE. In this case I am using IntelliJ build.gradle file should be similar to below. plugins { id 'java' id 'org.springframework.boot' version '3.3.5' id 'io.spring.dependency-management' version '1.1.6' } group = 'com.shastry.flyway.demo' version = '0.0.1-SNAPSHOT' java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.flywaydb:flyway-core' implementation 'org.flywaydb:flyway-database-hsqldb' compileOnly 'org.projectlombok:lombok' runtimeOnly 'org.hsqldb:hsqldb' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { useJUnitPlatform() } Configure application.properties or application.yml file with HSQL DB properties. spring: application: name: FlywayDemo datasource: url: jdbc:hsqldb:mem:testdb;sql.syntax_pgs=true jpa: show-sql: true hibernate: naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl Note: As for this example we are using DBeaver sample database which has CamelCasing for columns, setting spring.jpa.hibernate.naming.physical-strategy=org,hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl will prevent convering to Snake Case while executing SQL queries from the application. Create first flyway migration file V1__Initial_DB_tructure.sql by following the flyway file naming convention. DBeaverprovides us a sample database if installed. For our use case I have taken couple of tables with Data. Using HSQL for easy testing. -- Employee definition CREATE TABLE Employee ( EmployeeId INTEGER NOT NULL, LastName NVARCHAR(20) NOT NULL, FirstName NVARCHAR(20) NOT NULL, Title NVARCHAR(30), ReportsTo INTEGER, BirthDate DATETIME, HireDate DATETIME, Address NVARCHAR(70), City NVARCHAR(40), State NVARCHAR(40), Country NVARCHAR(40), PostalCode NVARCHAR(10), Phone NVARCHAR(24), Fax NVARCHAR(24), Email NVARCHAR(60), CONSTRAINT PK_Employee PRIMARY KEY (EmployeeId), FOREIGN KEY (ReportsTo) REFERENCES Employee (EmployeeId) ON DELETE NO ACTION ON UPDATE NO ACTION ); CREATE UNIQUE INDEX IPK_Employee ON Employee(EmployeeId); CREATE INDEX IFK_EmployeeReportsTo ON Employee (ReportsTo); INSERT INTO Employee (EmployeeId,LastName,FirstName,Title,ReportsTo,BirthDate,HireDate,Address,City,State,Country,PostalCode,Phone,Fax,Email) VALUES (1,'Adams','Andrew','General Manager',NULL,'1962-02-18 00:00:00','2002-08-14 00:00:00','11120 Jasper Ave NW','Edmonton','AB','Canada','T5K 2N1','+1 (780) 428-9482','+1 (780) 428-3457','andrew@chinookcorp.com'), (2,'Edwards','Nancy','Sales Manager',1,'1958-12-08 00:00:00','2002-05-01 00:00:00','825 8 Ave SW','Calgary','AB','Canada','T2P 2T3','+1 (403) 262-3443','+1 (403) 262-3322','nancy@chinookcorp.com'), (3,'Peacock','Jane','Sales Support Agent',2,'1973-08-29 00:00:00','2002-04-01 00:00:00','1111 6 Ave SW','Calgary','AB','Canada','T2P 5M5','+1 (403) 262-3443','+1 (403) 262-6712','jane@chinookcorp.com'), (4,'Park','Margaret','Sales Support Agent',2,'1947-09-19 00:00:00','2003-05-03 00:00:00','683 10 Street SW','Calgary','AB','Canada','T2P 5G3','+1 (403) 263-4423','+1 (403) 263-4289','margaret@chinookcorp.com'), (5,'Johnson','Steve','Sales Support Agent',2,'1965-03-03 00:00:00','2003-10-17 00:00:00','7727B 41 Ave','Calgary','AB','Canada','T3B 1Y7','1 (780) 836-9987','1 (780) 836-9543','steve@chinookcorp.com'), (6,'Mitchell','Michael','IT Manager',1,'1973-07-01 00:00:00','2003-10-17 00:00:00','5827 Bowness Road NW','Calgary','AB','Canada','T3B 0C5','+1 (403) 246-9887','+1 (403) 246-9899','michael@chinookcorp.com'), (7,'King','Robert','IT Staff',6,'1970-05-29 00:00:00','2004-01-02 00:00:00','590 Columbia Boulevard West','Lethbridge','AB','Canada','T1K 5N8','+1 (403) 456-9986','+1 (403) 456-8485','robert@chinookcorp.com'), (8,'

Apr 20, 2025 - 16:10
 0
Flyway Set-up and Integration with Spring Boot, a simple Hands-On

This article is about how to setup and integrate flyway migration tool to manage Database Schema in a Spring Boot application with simple setup. Here we use HSQL runtime database to minimize the setup and to have quick hands-on.

Prerequisites:

Below are the dependencies for this sample Flyway demo. Used https://start.spring.io/ to create the Spring Boot application.

  • JDK 17
  • Gradle-Groovy
  • HSQL Database
  • Spring boot Starter Web
  • Spring boot Starter Data JPA
  • Lombok
  • Flyway Migration

Spring Boot project config

Below is the sample Project structure.

Spring boot project structure

1. Create Database Baseline/V1:
Follow the below steps to integrate and test Flyway and create DB baseline.

  • Download/Generate the Spring boot project with prerequisites mentioned above and import it to any IDE. In this case I am using IntelliJ
  • build.gradle file should be similar to below.
plugins {
 id 'java'
 id 'org.springframework.boot' version '3.3.5'
 id 'io.spring.dependency-management' version '1.1.6'
}

group = 'com.shastry.flyway.demo'
version = '0.0.1-SNAPSHOT'

java {
 toolchain {
  languageVersion = JavaLanguageVersion.of(17)
 }
}

configurations {
 compileOnly {
  extendsFrom annotationProcessor
 }
}

repositories {
 mavenCentral()
}

dependencies {
 implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
 implementation 'org.springframework.boot:spring-boot-starter-web'
 implementation 'org.flywaydb:flyway-core'
 implementation 'org.flywaydb:flyway-database-hsqldb'
 compileOnly 'org.projectlombok:lombok'
 runtimeOnly 'org.hsqldb:hsqldb'
 annotationProcessor 'org.projectlombok:lombok'
 testImplementation 'org.springframework.boot:spring-boot-starter-test'
 testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
 useJUnitPlatform()
}
  • Configure application.properties or application.yml file with HSQL DB properties.
spring:
  application:
    name: FlywayDemo
  datasource:
    url: jdbc:hsqldb:mem:testdb;sql.syntax_pgs=true
  jpa:
    show-sql: true
    hibernate:
      naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Note:
As for this example we are using DBeaver sample database which has CamelCasing for columns, setting
spring.jpa.hibernate.naming.physical-strategy=org,hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
will prevent convering to Snake Case while executing SQL queries from the application.

  • Create first flyway migration file V1__Initial_DB_tructure.sql
  • by following the flyway file naming convention. DBeaverprovides us a sample database if installed. For our use case I have taken couple of tables with Data. Using HSQL for easy testing.
-- Employee definition
CREATE TABLE Employee
(
    EmployeeId INTEGER  NOT NULL,
    LastName NVARCHAR(20)  NOT NULL,
    FirstName NVARCHAR(20)  NOT NULL,
    Title NVARCHAR(30),
    ReportsTo INTEGER,
    BirthDate DATETIME,
    HireDate DATETIME,
    Address NVARCHAR(70),
    City NVARCHAR(40),
    State NVARCHAR(40),
    Country NVARCHAR(40),
    PostalCode NVARCHAR(10),
    Phone NVARCHAR(24),
    Fax NVARCHAR(24),
    Email NVARCHAR(60),
    CONSTRAINT PK_Employee PRIMARY KEY  (EmployeeId),
    FOREIGN KEY (ReportsTo) REFERENCES Employee (EmployeeId)
    ON DELETE NO ACTION ON UPDATE NO ACTION
    );

CREATE UNIQUE INDEX IPK_Employee ON Employee(EmployeeId);
CREATE INDEX IFK_EmployeeReportsTo ON Employee (ReportsTo);

INSERT INTO Employee (EmployeeId,LastName,FirstName,Title,ReportsTo,BirthDate,HireDate,Address,City,State,Country,PostalCode,Phone,Fax,Email) VALUES
(1,'Adams','Andrew','General Manager',NULL,'1962-02-18 00:00:00','2002-08-14 00:00:00','11120 Jasper Ave NW','Edmonton','AB','Canada','T5K 2N1','+1 (780) 428-9482','+1 (780) 428-3457','andrew@chinookcorp.com'),
(2,'Edwards','Nancy','Sales Manager',1,'1958-12-08 00:00:00','2002-05-01 00:00:00','825 8 Ave SW','Calgary','AB','Canada','T2P 2T3','+1 (403) 262-3443','+1 (403) 262-3322','nancy@chinookcorp.com'),
(3,'Peacock','Jane','Sales Support Agent',2,'1973-08-29 00:00:00','2002-04-01 00:00:00','1111 6 Ave SW','Calgary','AB','Canada','T2P 5M5','+1 (403) 262-3443','+1 (403) 262-6712','jane@chinookcorp.com'),
(4,'Park','Margaret','Sales Support Agent',2,'1947-09-19 00:00:00','2003-05-03 00:00:00','683 10 Street SW','Calgary','AB','Canada','T2P 5G3','+1 (403) 263-4423','+1 (403) 263-4289','margaret@chinookcorp.com'),
(5,'Johnson','Steve','Sales Support Agent',2,'1965-03-03 00:00:00','2003-10-17 00:00:00','7727B 41 Ave','Calgary','AB','Canada','T3B 1Y7','1 (780) 836-9987','1 (780) 836-9543','steve@chinookcorp.com'),
(6,'Mitchell','Michael','IT Manager',1,'1973-07-01 00:00:00','2003-10-17 00:00:00','5827 Bowness Road NW','Calgary','AB','Canada','T3B 0C5','+1 (403) 246-9887','+1 (403) 246-9899','michael@chinookcorp.com'),
(7,'King','Robert','IT Staff',6,'1970-05-29 00:00:00','2004-01-02 00:00:00','590 Columbia Boulevard West','Lethbridge','AB','Canada','T1K 5N8','+1 (403) 456-9986','+1 (403) 456-8485','robert@chinookcorp.com'),
(8,'Callahan','Laura','IT Staff',6,'1968-01-09 00:00:00','2004-03-04 00:00:00','923 7 ST NW','Lethbridge','AB','Canada','T1H 1Y8','+1 (403) 467-3351','+1 (403) 467-8772','laura@chinookcorp.com');
  • Create sample API with Employee.java pojo, EmployeeRepo.java repo, EmployeeService.java service and EmployeeController.java controller.
package com.shastry.flyway.demo.FlywayDemo.model;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import java.time.OffsetDateTime;

@Data
@Entity
@Table
public class Employee {

    @Id
    private Integer employeeId;
    private String firstName;
    private String lastName;
    private String title;
    private Integer reportsTo;
    private OffsetDateTime birthDate;
    private OffsetDateTime hireDate;
    private String address;
    private String city;
    private String state;
    private String country;
    private String postalCode;
    private String phone;
    private String fax;
    private String email;
}
package com.shastry.flyway.demo.FlywayDemo.repo;

import com.shastry.flyway.demo.FlywayDemo.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepo extends JpaRepository {
}
package com.shastry.flyway.demo.FlywayDemo.service;

import com.shastry.flyway.demo.FlywayDemo.model.Employee;
import com.shastry.flyway.demo.FlywayDemo.repo.EmployeeRepo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class EmployeeService {

    private final EmployeeRepo employeeRepo;

    public Employee getEmployee(Integer id) {
        return employeeRepo.findById(id).orElse(null);
    }

    public List getAllEmployees() {
        return employeeRepo.findAll();
    }
}
package com.shastry.flyway.demo.FlywayDemo.controller;

import com.shastry.flyway.demo.FlywayDemo.model.Employee;
import com.shastry.flyway.demo.FlywayDemo.service.EmployeeService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/v1/employee")
@RequiredArgsConstructor
public class EmployeeController {

    private final EmployeeService employeeService;

    @GetMapping
    public List list() {
        return employeeService.getAllEmployees();
    }

    @GetMapping("/{employeeId}")
    public Employee get(@PathVariable Integer employeeId) {
        return employeeService.getEmployee(employeeId);
    }

}
  • Run the Spring boot application and verify the logs to check if the flyway v1 sql is executed during server startup. If application started successfully, below log be displayed.
  • Below logs mentions it successfully applied DB migration script.
2024-10-27T12:42:29.014+05:30  INFO 51719 --- [FlywayDemo] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:hsqldb:mem:testdb;sql.syntax_pgs=true (HSQL Database Engine 2.7)
2024-10-27T12:42:29.030+05:30  INFO 51719 --- [FlywayDemo] [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Schema history table "PUBLIC"."flyway_schema_history" does not exist yet
2024-10-27T12:42:29.031+05:30  INFO 51719 --- [FlywayDemo] [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.007s)
2024-10-27T12:42:29.034+05:30  INFO 51719 --- [FlywayDemo] [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "PUBLIC"."flyway_schema_history" ...
2024-10-27T12:42:29.045+05:30  INFO 51719 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "PUBLIC": << Empty Schema >>
2024-10-27T12:42:29.052+05:30  INFO 51719 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version "1 - Initial DB Structure"
2024-10-27T12:42:29.078+05:30  INFO 51719 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "PUBLIC", now at version v1 (execution time 00:00.019s)
  • Test the employee endpoints to verify if the SQL in the flyway is executed and application is able to access.
sumanth.shastry ~ % curl --location 'http://localhost:8080/api/v1/employee'
[{"employeeId":1,"firstName":"Andrew","lastName":"Adams","title":"General Manager","reportsTo":null,"birthDate":"1962-02-18T00:00:00Z","hireDate":"2002-08-14T00:00:00Z","address":"11120 Jasper Ave NW","city":"Edmonton","state":"AB","country":"Canada","postalCode":"T5K 2N1","phone":"+1 (780) 428-9482","fax":"+1 (780) 428-3457","email":"andrew@chinookcorp.com"},{"employeeId":2,"firstName":"Nancy","lastName":"Edwards","title":"Sales Manager","reportsTo":1,"birthDate":"1958-12-08T00:00:00Z","hireDate":"2002-05-01T00:00:00Z","address":"825 8 Ave SW","city":"Calgary","state":"AB","country":"Canada","postalCode":"T2P 2T3","phone":"+1 (403) 262-3443","fax":"+1 (403) 262-3322","email":"nancy@chinookcorp.com"},{"employeeId":3,"firstName":"Jane","lastName":"Peacock","title":"Sales Support Agent","reportsTo":2,"birthDate":"1973-08-29T00:00:00Z","hireDate":"2002-04-01T00:00:00Z","address":"1111 6 Ave SW","city":"Calgary","state":"AB","country":"Canada","postalCode":"T2P 5M5","phone":"+1 (403) 262-3443","fax":"+1 (403) 262-6712","email":"jane@chinookcorp.com"},{"employeeId":4,"firstName":"Margaret","lastName":"Park","title":"Sales Support Agent","reportsTo":2,"birthDate":"1947-09-19T00:00:00Z","hireDate":"2003-05-03T00:00:00Z","address":"683 10 Street SW","city":"Calgary","state":"AB","country":"Canada","postalCode":"T2P 5G3","phone":"+1 (403) 263-4423","fax":"+1 (403) 263-4289","email":"margaret@chinookcorp.com"},{"employeeId":5,"firstName":"Steve","lastName":"Johnson","title":"Sales Support Agent","reportsTo":2,"birthDate":"1965-03-03T00:00:00Z","hireDate":"2003-10-17T00:00:00Z","address":"7727B 41 Ave","city":"Calgary","state":"AB","country":"Canada","postalCode":"T3B 1Y7","phone":"1 (780) 836-9987","fax":"1 (780) 836-9543","email":"steve@chinookcorp.com"},{"employeeId":6,"firstName":"Michael","lastName":"Mitchell","title":"IT Manager","reportsTo":1,"birthDate":"1973-07-01T00:00:00Z","hireDate":"2003-10-17T00:00:00Z","address":"5827 Bowness Road NW","city":"Calgary","state":"AB","country":"Canada","postalCode":"T3B 0C5","phone":"+1 (403) 246-9887","fax":"+1 (403) 246-9899","email":"michael@chinookcorp.com"},{"employeeId":7,"firstName":"Robert","lastName":"King","title":"IT Staff","reportsTo":6,"birthDate":"1970-05-29T00:00:00Z","hireDate":"2004-01-02T00:00:00Z","address":"590 Columbia Boulevard West","city":"Lethbridge","state":"AB","country":"Canada","postalCode":"T1K 5N8","phone":"+1 (403) 456-9986","fax":"+1 (403) 456-8485","email":"robert@chinookcorp.com"},{"employeeId":8,"firstName":"Laura","lastName":"Callahan","title":"IT Staff","reportsTo":6,"birthDate":"1968-01-09T00:00:00Z","hireDate":"2004-03-04T00:00:00Z","address":"923 7 ST NW","city":"Lethbridge","state":"AB","country":"Canada","postalCode":"T1H 1Y8","phone":"+1 (403) 467-3351","fax":"+1 (403) 467-8772","email":"laura@chinookcorp.com"}]%
sumanth.shastry ~ % curl --location 'http://localhost:8080/api/v1/employee/1'
{"employeeId":1,"firstName":"Andrew","lastName":"Adams","title":"General Manager","reportsTo":null,"birthDate":"1962-02-18T00:00:00Z","hireDate":"2002-08-14T00:00:00Z","address":"11120 Jasper Ave NW","city":"Edmonton","state":"AB","country":"Canada","postalCode":"T5K 2N1","phone":"+1 (780) 428-9482","fax":"+1 (780) 428-3457","email":"andrew@chinookcorp.com"}%

2. Create Flyway V2 migration:

Follow the below steps to create 2nd migration file.

  • Create flyway migration file V2__Create_Customer_Table.sql similar to previous section.
-- Customer definition

CREATE TABLE Customer
(
    CustomerId INTEGER  NOT NULL,
    FirstName NVARCHAR(40)  NOT NULL,
    LastName NVARCHAR(20)  NOT NULL,
    Company NVARCHAR(80),
    Address NVARCHAR(70),
    City NVARCHAR(40),
    State NVARCHAR(40),
    Country NVARCHAR(40),
    PostalCode NVARCHAR(10),
    Phone NVARCHAR(24),
    Fax NVARCHAR(24),
    Email NVARCHAR(60)  NOT NULL,
    SupportRepId INTEGER,
    CONSTRAINT PK_Customer PRIMARY KEY  (CustomerId),
    FOREIGN KEY (SupportRepId) REFERENCES Employee (EmployeeId)
    ON DELETE NO ACTION ON UPDATE NO ACTION
    );

CREATE UNIQUE INDEX IPK_Customer ON Customer(CustomerId);
CREATE INDEX IFK_CustomerSupportRepId ON Customer (SupportRepId);

INSERT INTO Customer (CustomerId,FirstName,LastName,Company,Address,City,State,Country,PostalCode,Phone,Fax,Email,SupportRepId) VALUES
(1,'Luís','Gonçalves','Embraer - Empresa Brasileira de Aeronáutica S.A.','Av. Brigadeiro Faria Lima, 2170','São José dos Campos','SP','Brazil','12227-000','+55 (12) 3923-5555','+55 (12) 3923-5566','luisg@embraer.com.br',3),
(2,'Leonie','Köhler',NULL,'Theodor-Heuss-Straße 34','Stuttgart',NULL,'Germany','70174','+49 0711 2842222',NULL,'leonekohler@surfeu.de',5),
(3,'François','Tremblay',NULL,'1498 rue Bélanger','Montréal','QC','Canada','H2G 1A7','+1 (514) 721-4711',NULL,'ftremblay@gmail.com',3),
(4,'Bjørn','Hansen',NULL,'Ullevålsveien 14','Oslo',NULL,'Norway','0171','+47 22 44 22 22',NULL,'bjorn.hansen@yahoo.no',4),
(5,'František','Wichterlová','JetBrains s.r.o.','Klanova 9/506','Prague',NULL,'Czech Republic','14700','+420 2 4172 5555','+420 2 4172 5555','frantisekw@jetbrains.com',4),
(6,'Helena','Holý',NULL,'Rilská 3174/6','Prague',NULL,'Czech Republic','14300','+420 2 4177 0449',NULL,'hholy@gmail.com',5),
(7,'Astrid','Gruber',NULL,'Rotenturmstraße 4, 1010 Innere Stadt','Vienne',NULL,'Austria','1010','+43 01 5134505',NULL,'astrid.gruber@apple.at',5),
(8,'Daan','Peeters',NULL,'Grétrystraat 63','Brussels',NULL,'Belgium','1000','+32 02 219 03 03',NULL,'daan_peeters@apple.be',4),
(9,'Kara','Nielsen',NULL,'Sønder Boulevard 51','Copenhagen',NULL,'Denmark','1720','+453 3331 9991',NULL,'kara.nielsen@jubii.dk',4),
(10,'Eduardo','Martins','Woodstock Discos','Rua Dr. Falcão Filho, 155','São Paulo','SP','Brazil','01007-010','+55 (11) 3033-5446','+55 (11) 3033-4564','eduardo@woodstock.com.br',4);
INSERT INTO Customer (CustomerId,FirstName,LastName,Company,Address,City,State,Country,PostalCode,Phone,Fax,Email,SupportRepId) VALUES
(11,'Alexandre','Rocha','Banco do Brasil S.A.','Av. Paulista, 2022','São Paulo','SP','Brazil','01310-200','+55 (11) 3055-3278','+55 (11) 3055-8131','alero@uol.com.br',5),
(12,'Roberto','Almeida','Riotur','Praça Pio X, 119','Rio de Janeiro','RJ','Brazil','20040-020','+55 (21) 2271-7000','+55 (21) 2271-7070','roberto.almeida@riotur.gov.br',3),
(13,'Fernanda','Ramos',NULL,'Qe 7 Bloco G','Brasília','DF','Brazil','71020-677','+55 (61) 3363-5547','+55 (61) 3363-7855','fernadaramos4@uol.com.br',4),
(14,'Mark','Philips','Telus','8210 111 ST NW','Edmonton','AB','Canada','T6G 2C7','+1 (780) 434-4554','+1 (780) 434-5565','mphilips12@shaw.ca',5),
(15,'Jennifer','Peterson','Rogers Canada','700 W Pender Street','Vancouver','BC','Canada','V6C 1G8','+1 (604) 688-2255','+1 (604) 688-8756','jenniferp@rogers.ca',3),
(16,'Frank','Harris','Google Inc.','1600 Amphitheatre Parkway','Mountain View','CA','USA','94043-1351','+1 (650) 253-0000','+1 (650) 253-0000','fharris@google.com',4),
(17,'Jack','Smith','Microsoft Corporation','1 Microsoft Way','Redmond','WA','USA','98052-8300','+1 (425) 882-8080','+1 (425) 882-8081','jacksmith@microsoft.com',5),
(18,'Michelle','Brooks',NULL,'627 Broadway','New York','NY','USA','10012-2612','+1 (212) 221-3546','+1 (212) 221-4679','michelleb@aol.com',3),
(19,'Tim','Goyer','Apple Inc.','1 Infinite Loop','Cupertino','CA','USA','95014','+1 (408) 996-1010','+1 (408) 996-1011','tgoyer@apple.com',3),
(20,'Dan','Miller',NULL,'541 Del Medio Avenue','Mountain View','CA','USA','94040-111','+1 (650) 644-3358',NULL,'dmiller@comcast.com',4);
INSERT INTO Customer (CustomerId,FirstName,LastName,Company,Address,City,State,Country,PostalCode,Phone,Fax,Email,SupportRepId) VALUES
(21,'Kathy','Chase',NULL,'801 W 4th Street','Reno','NV','USA','89503','+1 (775) 223-7665',NULL,'kachase@hotmail.com',5),
(22,'Heather','Leacock',NULL,'120 S Orange Ave','Orlando','FL','USA','32801','+1 (407) 999-7788',NULL,'hleacock@gmail.com',4),
(23,'John','Gordon',NULL,'69 Salem Street','Boston','MA','USA','2113','+1 (617) 522-1333',NULL,'johngordon22@yahoo.com',4),
(24,'Frank','Ralston',NULL,'162 E Superior Street','Chicago','IL','USA','60611','+1 (312) 332-3232',NULL,'fralston@gmail.com',3),
(25,'Victor','Stevens',NULL,'319 N. Frances Street','Madison','WI','USA','53703','+1 (608) 257-0597',NULL,'vstevens@yahoo.com',5),
(26,'Richard','Cunningham',NULL,'2211 W Berry Street','Fort Worth','TX','USA','76110','+1 (817) 924-7272',NULL,'ricunningham@hotmail.com',4),
(27,'Patrick','Gray',NULL,'1033 N Park Ave','Tucson','AZ','USA','85719','+1 (520) 622-4200',NULL,'patrick.gray@aol.com',4),
(28,'Julia','Barnett',NULL,'302 S 700 E','Salt Lake City','UT','USA','84102','+1 (801) 531-7272',NULL,'jubarnett@gmail.com',5),
(29,'Robert','Brown',NULL,'796 Dundas Street West','Toronto','ON','Canada','M6J 1V1','+1 (416) 363-8888',NULL,'robbrown@shaw.ca',3),
(30,'Edward','Francis',NULL,'230 Elgin Street','Ottawa','ON','Canada','K2P 1L7','+1 (613) 234-3322',NULL,'edfrancis@yachoo.ca',3);
INSERT INTO Customer (CustomerId,FirstName,LastName,Company,Address,City,State,Country,PostalCode,Phone,Fax,Email,SupportRepId) VALUES
(31,'Martha','Silk',NULL,'194A Chain Lake Drive','Halifax','NS','Canada','B3S 1C5','+1 (902) 450-0450',NULL,'marthasilk@gmail.com',5),
(32,'Aaron','Mitchell',NULL,'696 Osborne Street','Winnipeg','MB','Canada','R3L 2B9','+1 (204) 452-6452',NULL,'aaronmitchell@yahoo.ca',4),
(33,'Ellie','Sullivan',NULL,'5112 48 Street','Yellowknife','NT','Canada','X1A 1N6','+1 (867) 920-2233',NULL,'ellie.sullivan@shaw.ca',3),
(34,'João','Fernandes',NULL,'Rua da Assunção 53','Lisbon',NULL,'Portugal',NULL,'+351 (213) 466-111',NULL,'jfernandes@yahoo.pt',4),
(35,'Madalena','Sampaio',NULL,'Rua dos Campeões Europeus de Viena, 4350','Porto',NULL,'Portugal',NULL,'+351 (225) 022-448',NULL,'masampaio@sapo.pt',4),
(36,'Hannah','Schneider',NULL,'Tauentzienstraße 8','Berlin',NULL,'Germany','10789','+49 030 26550280',NULL,'hannah.schneider@yahoo.de',5),
(37,'Fynn','Zimmermann',NULL,'Berger Straße 10','Frankfurt',NULL,'Germany','60316','+49 069 40598889',NULL,'fzimmermann@yahoo.de',3),
(38,'Niklas','Schröder',NULL,'Barbarossastraße 19','Berlin',NULL,'Germany','10779','+49 030 2141444',NULL,'nschroder@surfeu.de',3),
(39,'Camille','Bernard',NULL,'4, Rue Milton','Paris',NULL,'France','75009','+33 01 49 70 65 65',NULL,'camille.bernard@yahoo.fr',4),
(40,'Dominique','Lefebvre',NULL,'8, Rue Hanovre','Paris',NULL,'France','75002','+33 01 47 42 71 71',NULL,'dominiquelefebvre@gmail.com',4);
INSERT INTO Customer (CustomerId,FirstName,LastName,Company,Address,City,State,Country,PostalCode,Phone,Fax,Email,SupportRepId) VALUES
(41,'Marc','Dubois',NULL,'11, Place Bellecour','Lyon',NULL,'France','69002','+33 04 78 30 30 30',NULL,'marc.dubois@hotmail.com',5),
(42,'Wyatt','Girard',NULL,'9, Place Louis Barthou','Bordeaux',NULL,'France','33000','+33 05 56 96 96 96',NULL,'wyatt.girard@yahoo.fr',3),
(43,'Isabelle','Mercier',NULL,'68, Rue Jouvence','Dijon',NULL,'France','21000','+33 03 80 73 66 99',NULL,'isabelle_mercier@apple.fr',3),
(44,'Terhi','Hämäläinen',NULL,'Porthaninkatu 9','Helsinki',NULL,'Finland','00530','+358 09 870 2000',NULL,'terhi.hamalainen@apple.fi',3),
(45,'Ladislav','Kovács',NULL,'Erzsébet krt. 58.','Budapest',NULL,'Hungary','H-1073',NULL,NULL,'ladislav_kovacs@apple.hu',3),
(46,'Hugh','O''Reilly',NULL,'3 Chatham Street','Dublin','Dublin','Ireland',NULL,'+353 01 6792424',NULL,'hughoreilly@apple.ie',3),
(47,'Lucas','Mancini',NULL,'Via Degli Scipioni, 43','Rome','RM','Italy','00192','+39 06 39733434',NULL,'lucas.mancini@yahoo.it',5),
(48,'Johannes','Van der Berg',NULL,'Lijnbaansgracht 120bg','Amsterdam','VV','Netherlands','1016','+31 020 6223130',NULL,'johavanderberg@yahoo.nl',5),
(49,'Stanisław','Wójcik',NULL,'Ordynacka 10','Warsaw',NULL,'Poland','00-358','+48 22 828 37 39',NULL,'stanisław.wójcik@wp.pl',4),
(50,'Enrique','Muñoz',NULL,'C/ San Bernardo 85','Madrid',NULL,'Spain','28015','+34 914 454 454',NULL,'enrique_munoz@yahoo.es',5);
INSERT INTO Customer (CustomerId,FirstName,LastName,Company,Address,City,State,Country,PostalCode,Phone,Fax,Email,SupportRepId) VALUES
(51,'Joakim','Johansson',NULL,'Celsiusg. 9','Stockholm',NULL,'Sweden','11230','+46 08-651 52 52',NULL,'joakim.johansson@yahoo.se',5),
(52,'Emma','Jones',NULL,'202 Hoxton Street','London',NULL,'United Kingdom','N1 5LH','+44 020 7707 0707',NULL,'emma_jones@hotmail.com',3),
(53,'Phil','Hughes',NULL,'113 Lupus St','London',NULL,'United Kingdom','SW1V 3EN','+44 020 7976 5722',NULL,'phil.hughes@gmail.com',3),
(54,'Steve','Murray',NULL,'110 Raeburn Pl','Edinburgh ',NULL,'United Kingdom','EH4 1HH','+44 0131 315 3300',NULL,'steve.murray@yahoo.uk',5),
(55,'Mark','Taylor',NULL,'421 Bourke Street','Sidney','NSW','Australia','2010','+61 (02) 9332 3633',NULL,'mark.taylor@yahoo.au',4),
(56,'Diego','Gutiérrez',NULL,'307 Macacha Güemes','Buenos Aires',NULL,'Argentina','1106','+54 (0)11 4311 4333',NULL,'diego.gutierrez@yahoo.ar',4),
(57,'Luis','Rojas',NULL,'Calle Lira, 198','Santiago',NULL,'Chile',NULL,'+56 (0)2 635 4444',NULL,'luisrojas@yahoo.cl',5),
(58,'Manoj','Pareek',NULL,'12,Community Centre','Delhi',NULL,'India','110017','+91 0124 39883988',NULL,'manoj.pareek@rediff.com',3),
(59,'Puja','Srivastava',NULL,'3,Raj Bhavan Road','Bangalore',NULL,'India','560001','+91 080 22289999',NULL,'puja_srivastava@yahoo.in',3);
  • Create Customer.java pojo, CustomerRepo.java repo, CustomerService.java service and CustomerController.java controller.
package com.shastry.flyway.demo.FlywayDemo.model;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;

@Data
@Entity
@Table
public class Customer {

    @Id
    private Integer customerId;
    private String firstName;
    private String lastName;
    private String company;
    private String address;
    private String city;
    private String state;
    private String country;
    private String postalCode;
    private String phone;
    private String fax;
    private String email;
    private Integer supportRepId;
}
package com.shastry.flyway.demo.FlywayDemo.repo;

import com.shastry.flyway.demo.FlywayDemo.model.Customer;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CustomerRepo extends JpaRepository {
}
package com.shastry.flyway.demo.FlywayDemo.service;

import com.shastry.flyway.demo.FlywayDemo.model.Customer;
import com.shastry.flyway.demo.FlywayDemo.repo.CustomerRepo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class CustomerService {

    private final CustomerRepo customerRepo;

    public Customer get(Integer id) {
        return customerRepo.findById(id).orElse(null);
    }

    public List getAllCustomers() {
        return customerRepo.findAll();
    }
}
package com.shastry.flyway.demo.FlywayDemo.controller;

import com.shastry.flyway.demo.FlywayDemo.model.Customer;
import com.shastry.flyway.demo.FlywayDemo.service.CustomerService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/v1/customer")
@RequiredArgsConstructor
public class CustomerController {

    private final CustomerService customerService;

    @GetMapping("/{customerId}")
    public Customer get(@PathVariable Integer customerId) {
        return customerService.get(customerId);
    }

    @GetMapping
    public List getAll() {
        return customerService.getAllCustomers();
    }
}
  • Run the Spring boot application and verify the logs to check if the flyway v1 and v2 sql are executed during server startup. If application started successfully, below log be displayed.
2024-10-27T12:42:29.014+05:30  INFO 51719 --- [FlywayDemo] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:hsqldb:mem:testdb;sql.syntax_pgs=true (HSQL Database Engine 2.7)
2024-10-27T12:56:23.039+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Schema history table "PUBLIC"."flyway_schema_history" does not exist yet
2024-10-27T12:56:23.040+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.006s)
2024-10-27T12:56:23.043+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "PUBLIC"."flyway_schema_history" ...
2024-10-27T12:56:23.054+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "PUBLIC": << Empty Schema >>
2024-10-27T12:56:23.077+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version "1 - Initial DB Structure"
2024-10-27T12:56:23.098+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version "2 - Create Customer Table"
2024-10-27T12:56:23.104+05:30  INFO 54805 --- [FlywayDemo] [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema "PUBLIC", now at version v2 (execution time 00:00.004s)
  • Test the employee endpoints to verify if the SQL in the flyway is executed and application is able to access.
sumanth.shastry ~ % curl --location 'http://localhost:8080/api/v1/customer/1'
{"customerId":1,"firstName":"Luís","lastName":"Gonçalves","company":"Embraer - Empresa Brasileira de Aeronáutica S.A.","address":"Av. Brigadeiro Faria Lima, 2170","city":"São José dos Campos","state":"SP","country":"Brazil","postalCode":"12227-000","phone":"+55 (12) 3923-5555","fax":"+55 (12) 3923-5566","email":"luisg@embraer.com.br","supportRepId":3}%

Conclusion:

In this article, we learned a simple, easy hands-on and integrating Flyway migration with Spring boot.

Find the respective code over the Github.