FlyWay tutorial for Spring Boot users

This tutorial will show you how to perform FlyWay database migrations using Spring Boot and PostgreSQL Database.

Flyway is an open-source library that lets you to automate version-based database migrations. Flyway records of all applied migrations into your RDBMs so that it can detect and execute the required migration steps to update your database to the latest version. You can trigger Flyway in several ways: either use its command line client or integrate it into your Java application. In this post, I will show you how to integrate a migration in your Spring Boot application.

Starting PostgreSQL Database

We will be using PostgreSQL for our Migration examples. The simplest way to get started, is to launch it as Docker container:

$ docker run --rm=true --name flyway_test -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p 5432:5432 postgres:10.5 

Check that the PostgreSQL process is active:

$ docker ps CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES 3c22fb3e2adb        postgres:10.5       "docker-entrypoint..."   21 minutes ago      Up 21 minutes       0.0.0.0:5432->5432/tcp   flyway_test 

Create the Spring Boot project

Now it’s time to create the Spring Boot project that will perform the migration. From the shell (or using the Spring Boot Initializr) execute:

$ spring init -dweb,data-jpa,postgresql,flyway spring-flyway-demo 

Ok, you will end with a nice project which contains all the required dependencies:

<?xml version="1.0" encoding="UTF-8"?><project>
   	
   <dependencies>
       		
      <dependency>
          			
         <groupId>org.springframework.boot</groupId>
          			
         <artifactId>spring-boot-starter-data-jpa</artifactId>
          		
      </dependency>
       		
      <dependency>
          			
         <groupId>org.springframework.boot</groupId>
          			
         <artifactId>spring-boot-starter-web</artifactId>
          		
      </dependency>
       		
      <dependency>
          			
         <groupId>org.flywaydb</groupId>
          			
         <artifactId>flyway-core</artifactId>
          		
      </dependency>
        		
      <dependency>
          			
         <groupId>org.postgresql</groupId>
          			
         <artifactId>postgresql</artifactId>
          			
         <scope>runtime</scope>
          		
      </dependency>
       		
      <dependency>
          			
         <groupId>org.springframework.boot</groupId>
          			
         <artifactId>spring-boot-starter-test</artifactId>
          			
         <scope>test</scope>
          		
      </dependency>
       	
   </dependencies>
    
</project>

Configuring the Spring Boot Project

Next step will be adding the Datasource settings in the application.properties file which will be read by FlyWay to perform the migration:

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres spring.datasource.username=postgres spring.datasource.password=postgres spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true 

Notice the last parameter spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true which is required to avoid the annoying error:

Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException 

Ok, now let’s add Entity classes that are part of our Database schema. In our case, just this class:

package com.example.springflywaydemo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Account {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  String userId;

  String username;
  String password;
  String country;

  public String getUserId() {
    return userId;
  }

  public void setUserId(String userId) {
    this.userId = userId;
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getCountry() {
    return country;
  }

  public void setCountry(String country) {
    this.country = country;
  }
}

Add Migration files

Migration files are searched by FlyWay, by default, in this path src/main/resources/db/migration so let’s create it from the root of our project:

$ mkdir -p src/main/resources/db/migration 

Within the migration folder, we will add a subfolder for each new migration we want to add:

├── src │   ├── main │   │   ├── java │   │   │   └── com │   │   │       └── example │   │   │           └── springflywaydemo │   │   │               ├── Account.java │   │   │               └── DemoApplication.java │   │   └── resources │   │       ├── application.properties │   │       ├── db │   │       │   └── migration │   │       │       ├── release_1 │   │       │       │   └── V1_1__create_account_table.sql │   │       │       └── release_2 │   │       │           └── V1_2__insert_account_table.sql │   │       ├── static  

The first SQL script (V1_1__create_account_table.sql) contains the DDL of a table:

CREATE TABLE account(    user_id VARCHAR PRIMARY KEY,    username VARCHAR (50) UNIQUE NOT NULL,    password VARCHAR (50) NOT NULL,    country VARCHAR (355) NOT NULL ); 

The second script (V1_2__insert_account_table.sql), executes a couple of inserts in the Table:

INSERT into account ( user_id, username, password, country) VALUES ('a1234567','frank','smith','usa'); INSERT into account ( user_id, username, password, country) VALUES ('bc123454','mark','twain','usa'); 

To trigger the migration it’s enough to execute the install phase, that will trigger our tests:

mvn clean install 

You should see in your Console logs:

o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 5.2.4 by Boxfuse com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting... com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed. o.f.c.internal.database.DatabaseFactory  : Database: jdbc:postgresql://localhost:5432/postgres (PostgreSQL 10.5) o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.013s) o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table: "public"."flyway_schema_history" o.f.core.internal.command.DbMigrate      : Current version of schema "public": << Empty Schema >> o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version 1.1 - create account table o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version 1.2 - insert account table o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema "public" (execution time 00:00.132s) 

Now, if we check into the Docker process and we log into the Database, we can see that the migration was completed successfully:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
3c22fb3e2adb        postgres:10.5       "docker-entrypoint..."   31 minutes ago      Up 31 minutes       0.0.0.0:5432->5432/tcp   flyway_test

$ docker exec -it 3c22fb3e2adb /bin/bash
root@3c22fb3e2adb:/# psql -U postgres
psql (10.5 (Debian 10.5-2.pgdg90+1))
Type "help" for help.

postgres=# \dt
                 List of relations
 Schema |         Name          | Type  |  Owner   
--------+-----------------------+-------+----------
 public | account               | table | postgres
 public | flyway_schema_history | table | postgres
(2 rows)

postgres=# select * from account;
 user_id  | username | password |      country      
----------+----------+----------+-----------------
 a1234567 | frank    | smith    | usa
 bc123454 | mark     | twain    | usa
(2 rows)

So What happened?

When the migration process starts, Flyway tries to locate its schema history table. As the database is empty, Flyway won’t find it and will create it instead.

You now have a database with a single empty table called flyway_schema_history.

Important! This table will be used to track the state of the database.

Immediately afterwards Flyway will scan the filesystem or the classpath to find migration files which can be written in either Sql or Java.

The migrations are then sorted based on their version number and applied in order, as you can see from the following picture

 

 

You can find the source code for both examples here: https://github.com/fmarchioni/masterspringboot/tree/master/flyway/spring-flyway-demo

FlyWay in Java Enterprise Applications

If you are looking for a tutorial of FlyWay with an Enterprise Application you can check this tutorial: http://www.mastertheboss.com/other/flyway/getting-started-with-flyway

Exit mobile version