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','[email protected]'),
(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','[email protected]'),
(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','[email protected]'),
(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','[email protected]'),
(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','[email protected]'),
(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','[email protected]'),
(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','[email protected]'),
(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','[email protected]');
  • 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":"[email protected]"},{"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":"[email protected]"},{"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":"[email protected]"},{"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":"[email protected]"},{"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":"[email protected]"},{"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":"[email protected]"},{"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":"[email protected]"},{"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":"[email protected]"}]%
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":"[email protected]"}%

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','[email protected]',3),
(2,'Leonie','Köhler',NULL,'Theodor-Heuss-Straße 34','Stuttgart',NULL,'Germany','70174','+49 0711 2842222',NULL,'[email protected]',5),
(3,'François','Tremblay',NULL,'1498 rue Bélanger','Montréal','QC','Canada','H2G 1A7','+1 (514) 721-4711',NULL,'[email protected]',3),
(4,'Bjørn','Hansen',NULL,'Ullevålsveien 14','Oslo',NULL,'Norway','0171','+47 22 44 22 22',NULL,'[email protected]',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','[email protected]',4),
(6,'Helena','Holý',NULL,'Rilská 3174/6','Prague',NULL,'Czech Republic','14300','+420 2 4177 0449',NULL,'[email protected]',5),
(7,'Astrid','Gruber',NULL,'Rotenturmstraße 4, 1010 Innere Stadt','Vienne',NULL,'Austria','1010','+43 01 5134505',NULL,'[email protected]',5),
(8,'Daan','Peeters',NULL,'Grétrystraat 63','Brussels',NULL,'Belgium','1000','+32 02 219 03 03',NULL,'[email protected]',4),
(9,'Kara','Nielsen',NULL,'Sønder Boulevard 51','Copenhagen',NULL,'Denmark','1720','+453 3331 9991',NULL,'[email protected]',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','[email protected]',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','[email protected]',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','[email protected]',3),
(13,'Fernanda','Ramos',NULL,'Qe 7 Bloco G','Brasília','DF','Brazil','71020-677','+55 (61) 3363-5547','+55 (61) 3363-7855','[email protected]',4),
(14,'Mark','Philips','Telus','8210 111 ST NW','Edmonton','AB','Canada','T6G 2C7','+1 (780) 434-4554','+1 (780) 434-5565','[email protected]',5),
(15,'Jennifer','Peterson','Rogers Canada','700 W Pender Street','Vancouver','BC','Canada','V6C 1G8','+1 (604) 688-2255','+1 (604) 688-8756','[email protected]',3),
(16,'Frank','Harris','Google Inc.','1600 Amphitheatre Parkway','Mountain View','CA','USA','94043-1351','+1 (650) 253-0000','+1 (650) 253-0000','[email protected]',4),
(17,'Jack','Smith','Microsoft Corporation','1 Microsoft Way','Redmond','WA','USA','98052-8300','+1 (425) 882-8080','+1 (425) 882-8081','[email protected]',5),
(18,'Michelle','Brooks',NULL,'627 Broadway','New York','NY','USA','10012-2612','+1 (212) 221-3546','+1 (212) 221-4679','[email protected]',3),
(19,'Tim','Goyer','Apple Inc.','1 Infinite Loop','Cupertino','CA','USA','95014','+1 (408) 996-1010','+1 (408) 996-1011','[email protected]',3),
(20,'Dan','Miller',NULL,'541 Del Medio Avenue','Mountain View','CA','USA','94040-111','+1 (650) 644-3358',NULL,'[email protected]',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,'[email protected]',5),
(22,'Heather','Leacock',NULL,'120 S Orange Ave','Orlando','FL','USA','32801','+1 (407) 999-7788',NULL,'[email protected]',4),
(23,'John','Gordon',NULL,'69 Salem Street','Boston','MA','USA','2113','+1 (617) 522-1333',NULL,'[email protected]',4),
(24,'Frank','Ralston',NULL,'162 E Superior Street','Chicago','IL','USA','60611','+1 (312) 332-3232',NULL,'[email protected]',3),
(25,'Victor','Stevens',NULL,'319 N. Frances Street','Madison','WI','USA','53703','+1 (608) 257-0597',NULL,'[email protected]',5),
(26,'Richard','Cunningham',NULL,'2211 W Berry Street','Fort Worth','TX','USA','76110','+1 (817) 924-7272',NULL,'[email protected]',4),
(27,'Patrick','Gray',NULL,'1033 N Park Ave','Tucson','AZ','USA','85719','+1 (520) 622-4200',NULL,'[email protected]',4),
(28,'Julia','Barnett',NULL,'302 S 700 E','Salt Lake City','UT','USA','84102','+1 (801) 531-7272',NULL,'[email protected]',5),
(29,'Robert','Brown',NULL,'796 Dundas Street West','Toronto','ON','Canada','M6J 1V1','+1 (416) 363-8888',NULL,'[email protected]',3),
(30,'Edward','Francis',NULL,'230 Elgin Street','Ottawa','ON','Canada','K2P 1L7','+1 (613) 234-3322',NULL,'[email protected]',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,'[email protected]',5),
(32,'Aaron','Mitchell',NULL,'696 Osborne Street','Winnipeg','MB','Canada','R3L 2B9','+1 (204) 452-6452',NULL,'[email protected]',4),
(33,'Ellie','Sullivan',NULL,'5112 48 Street','Yellowknife','NT','Canada','X1A 1N6','+1 (867) 920-2233',NULL,'[email protected]',3),
(34,'João','Fernandes',NULL,'Rua da Assunção 53','Lisbon',NULL,'Portugal',NULL,'+351 (213) 466-111',NULL,'[email protected]',4),
(35,'Madalena','Sampaio',NULL,'Rua dos Campeões Europeus de Viena, 4350','Porto',NULL,'Portugal',NULL,'+351 (225) 022-448',NULL,'[email protected]',4),
(36,'Hannah','Schneider',NULL,'Tauentzienstraße 8','Berlin',NULL,'Germany','10789','+49 030 26550280',NULL,'[email protected]',5),
(37,'Fynn','Zimmermann',NULL,'Berger Straße 10','Frankfurt',NULL,'Germany','60316','+49 069 40598889',NULL,'[email protected]',3),
(38,'Niklas','Schröder',NULL,'Barbarossastraße 19','Berlin',NULL,'Germany','10779','+49 030 2141444',NULL,'[email protected]',3),
(39,'Camille','Bernard',NULL,'4, Rue Milton','Paris',NULL,'France','75009','+33 01 49 70 65 65',NULL,'[email protected]',4),
(40,'Dominique','Lefebvre',NULL,'8, Rue Hanovre','Paris',NULL,'France','75002','+33 01 47 42 71 71',NULL,'[email protected]',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,'[email protected]',5),
(42,'Wyatt','Girard',NULL,'9, Place Louis Barthou','Bordeaux',NULL,'France','33000','+33 05 56 96 96 96',NULL,'[email protected]',3),
(43,'Isabelle','Mercier',NULL,'68, Rue Jouvence','Dijon',NULL,'France','21000','+33 03 80 73 66 99',NULL,'[email protected]',3),
(44,'Terhi','Hämäläinen',NULL,'Porthaninkatu 9','Helsinki',NULL,'Finland','00530','+358 09 870 2000',NULL,'[email protected]',3),
(45,'Ladislav','Kovács',NULL,'Erzsébet krt. 58.','Budapest',NULL,'Hungary','H-1073',NULL,NULL,'[email protected]',3),
(46,'Hugh','O''Reilly',NULL,'3 Chatham Street','Dublin','Dublin','Ireland',NULL,'+353 01 6792424',NULL,'[email protected]',3),
(47,'Lucas','Mancini',NULL,'Via Degli Scipioni, 43','Rome','RM','Italy','00192','+39 06 39733434',NULL,'[email protected]',5),
(48,'Johannes','Van der Berg',NULL,'Lijnbaansgracht 120bg','Amsterdam','VV','Netherlands','1016','+31 020 6223130',NULL,'[email protected]',5),
(49,'Stanisław','Wójcik',NULL,'Ordynacka 10','Warsaw',NULL,'Poland','00-358','+48 22 828 37 39',NULL,'stanisław.wó[email protected]',4),
(50,'Enrique','Muñoz',NULL,'C/ San Bernardo 85','Madrid',NULL,'Spain','28015','+34 914 454 454',NULL,'[email protected]',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,'[email protected]',5),
(52,'Emma','Jones',NULL,'202 Hoxton Street','London',NULL,'United Kingdom','N1 5LH','+44 020 7707 0707',NULL,'[email protected]',3),
(53,'Phil','Hughes',NULL,'113 Lupus St','London',NULL,'United Kingdom','SW1V 3EN','+44 020 7976 5722',NULL,'[email protected]',3),
(54,'Steve','Murray',NULL,'110 Raeburn Pl','Edinburgh ',NULL,'United Kingdom','EH4 1HH','+44 0131 315 3300',NULL,'[email protected]',5),
(55,'Mark','Taylor',NULL,'421 Bourke Street','Sidney','NSW','Australia','2010','+61 (02) 9332 3633',NULL,'[email protected]',4),
(56,'Diego','Gutiérrez',NULL,'307 Macacha Güemes','Buenos Aires',NULL,'Argentina','1106','+54 (0)11 4311 4333',NULL,'[email protected]',4),
(57,'Luis','Rojas',NULL,'Calle Lira, 198','Santiago',NULL,'Chile',NULL,'+56 (0)2 635 4444',NULL,'[email protected]',5),
(58,'Manoj','Pareek',NULL,'12,Community Centre','Delhi',NULL,'India','110017','+91 0124 39883988',NULL,'[email protected]',3),
(59,'Puja','Srivastava',NULL,'3,Raj Bhavan Road','Bangalore',NULL,'India','560001','+91 080 22289999',NULL,'[email protected]',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":"[email protected]","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.