Zero Downtime Deployment and Databases

Zero Downtime Deployment and Databases

This article explains in detail how to deal with database compatibility issues during deployment. We will tell you what can happen to your applications on production if you try to deploy without prior preparation. We will then walk through the application life cycle steps that are required to have zero downtime (approx. transl.: further - zero downtime). The result of our operations will be to apply a backwards incompatible database change in a backwards compatible way.

If you want to understand the code examples from the article, you can find them at GitHub.

Introduction

Zero downtime deployment

What is mystical zero downtime deployment? You could say it's when your app is deployed so that you can successfully bring a new version of the app into production without the user noticing it's unavailable. From a user and company point of view, this is the best possible deployment scenario as it allows new features to be introduced and bugs to be fixed without disruption.

How to achieve this? There are several ways, here is one of them:

  • deploy version #1 of your service
  • do a database migration
  • deploy version #2 of your service in parallel with version #1
  • once you see version #2 working as it should, remove version #1
  • ready!

Easy, isn't it? Unfortunately, it's not that easy, and we'll look at that in detail later. And now let's check another fairly common deployment process - blue green deployment.

Have you ever heard of blue green deployment? With Cloud Foundry, this is extremely easy to do. Just take a look at this articlewhere we describe this in more detail. Briefly summarizing, let's recall how to do blue green deployment:

  • provide two copies of your production code (“blue” and “green”);
  • direct all traffic to the blue environment, i.e. so that production URLs point there;
  • deploy and test all application changes in a green environment;
  • switch urls from blue to green environment

Blue green deployment is an approach that allows you to easily introduce new features without worrying that production will break. This is due to the fact that even if something happens, you can easily roll back to the previous environment by simply "flicking a switch".

After reading all of the above, you might be asking yourself: What does zero downtime have to do with Blue green deployments?

Well, they have quite a lot in common, since maintaining two copies of the same environment requires double the effort to maintain them. That's why some commands, as claimed Martin fowler, follow a variation of this approach:

another option is to use the same database, creating blue-green switches for the web and domain layers. Databases can often be a problem in this approach, especially when you need to change their schema to support a new version of the software.

And here we come to the main problem in this article. Data Bank. Let's look at this phrase again.

perform a database migration.

Now you have to ask yourself the question - what if changing the database is backwards incompatible? Won't my first version of the app break? In fact, that is exactly what will happen...

So, even with the huge benefits of zero downtime / blue green deployment, companies tend to follow the following safer deployment process for their applications:

  • prepare a package with a new version of the application
  • shut down running application
  • run scripts for database migration
  • deploy and run a new version of the application

In this article, we will detail how you can work with the database and code to take advantage of zero downtime deployment.

Database issues

If you have a stateless application that does not store any data in the database, you can get zero downtime deployment right away. Unfortunately, most software has to store data somewhere. This is why you should think twice before making any changes to the circuit. Before we get into the details of how to change the schema so that no downtime deployment is possible, let's first focus on the version control schema.

Version control scheme

In this article, we will use flyway as a version control tool (approx. per.: we are talking about database migrations). Naturally, we will also write a Spring Boot application that has built-in support for Flyway and will perform schema migration during application context setup. When using Flyway, you can store migration scripts in your projects folder (default in classpath:db/migration). Here you can see an example of such migration files

└── db
 └── migration
     ├── V1__init.sql
     ├── V2__Add_surname.sql
     ├── V3__Final_migration.sql
     └── V4__Remove_lastname.sql

In this example, we see 4 migration scenarios which, if they have not been executed before, will be executed one after the other when the application starts. Let's look at one of the files (V1__init.sql) as an example.

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Everything perfectly speaks for itself: you can use SQL to determine how your database should be modified. For more information about Spring Boot and Flyway check out Spring Boot Docs.

By using a version control tool with Spring Boot, you get 2 big benefits:

  • you separate database changes from code changes
  • the database migration happens along with the rollout of your application, i.e. your deployment process is simplified

Solving database problems

In the next section of the article, we will focus on two approaches to database changes.

  • backward incompatibility
  • backward compatibility

The first one will be considered as a warning not to do zero downtime deployment without prior preparation... The second one offers a solution to how you can deploy without downtime and at the same time maintain backward compatibility.

Our project we will be working on will be a simple Spring Boot Flyway application that has Person с first_name и last_name in the database (approx. trans.: Person is a table and first_name и last_name are the fields in it). We want to rename last_name в surname.

Assumptions

Before we get into the details, we need to make a couple of assumptions about our applications. The main result that we want to achieve will be a fairly simple process.

The note. Business PRO-TIP. Simplifying processes can save you a lot of money in support (the more people you have, the more money you can save)!

No database rollback required

This simplifies the deployment process (some database rollbacks are nearly impossible, such as deletion rollback). We prefer to only rollback applications. Thus, even if you have different databases (for example, SQL and NoSQL), your deployment pipeline will look the same.

It is necessary that it is ALWAYS possible to roll back the application one version back (no more)

Rollback should be done only when necessary. If there is a bug in the current version that is not easy to fix, we should be able to revert back to the latest working version. We assume that this latest working version is the previous one. Maintaining code and database compatibility for more than one rollout would be extremely difficult and costly.

Note. For greater readability, in this article we will change the major version of the application.

Step 1: Initial state

Application version: 1.0.0
DB version: v1

Comment

This will be the initial state of the application.

Database changes

DB contains last_name.

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Code changes

The application stores Person data in last_name:

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

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

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastname) {
        this.lastName = lastname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", lastName=" + this.lastName
                + "]";
    }
}

Backward incompatible column renaming

Let's look at an example of how to change the column name:

Attention. The following example will intentionally break. We show this to demonstrate the problem of database compatibility.

Application version: 2.0.0.BAD

DB version: v2bad

Comment

The current changes do NOT allow us to run two instances (old and new) at the same time. Thus, zero downtime deployment will be difficult to achieve (if you take into account the assumptions, this is actually impossible).

A/B testing

The current situation is that we have a version application 1.0.0, deployed in the sale, and the database v1. We have to deploy a second instance of the application, version 2.0.0.BAD, and update the database to v2bad.

Steps:

  1. deployed a new version application instance 2.0.0.BADwhich updates the database to v2bad
  2. in the database v2bad column last_name no longer exists - it has been changed to surname
  3. the database and application upgrade was successful and some instances are running in 1.0.0, others in 2.0.0.BAD. Everything is DB related. v2bad
  4. all instances of the version 1.0.0 will start throwing errors because they will try to insert data into the column last_name, which is no more
  5. all instances of the version 2.0.0.BAD will work without problems

As you can see, if we make backward incompatible changes to the database and the application, A/B testing is not possible.

Application Rollback

Let's assume that after trying to do an A/B deployment (approx. per .: probably, here the author meant A / B testing) we decided that we need to roll back the application to the version 1.0.0. Let's say we don't want to rollback the database.

Steps:

  1. we stop the version application instance 2.0.0.BAD
  2. the database is still v2bad
  3. since the version 1.0.0 does not understand what is surname, we will see errors
  4. hell broke loose, we can't go back anymore

As you can see, if we make backward incompatible changes to the database and application, we cannot roll back to the previous version.

Script execution logs

Backward incompatible scenario:

01) Run 1.0.0
02) Wait for the app (1.0.0) to boot
03) Generate a person by calling POST localhost:9991/person to version 1.0.0
04) Run 2.0.0.BAD
05) Wait for the app (2.0.0.BAD) to boot
06) Generate a person by calling POST localhost:9991/person to version 1.0.0 <-- this should fail
07) Generate a person by calling POST localhost:9992/person to version 2.0.0.BAD <-- this should pass

Starting app in version 1.0.0
Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

{"firstName":"b73f639f-e176-4463-bf26-1135aace2f57","lastName":"b73f639f-e176-4463-bf26-1135aace2f57"}

Starting app in version 2.0.0.BAD
Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

curl: (22) The requested URL returned error: 500 Internal Server Error

Generate a person in version 2.0.0.BAD
Sending a post to 127.0.0.1:9995/person. This is the response:

{"firstName":"e156be2e-06b6-4730-9c43-6e14cfcda125","surname":"e156be2e-06b6-4730-9c43-6e14cfcda125"}

Database changes

Migration script that renames last_name в surname

Source Flyway script:

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Script that renames last_name.

-- This change is backward incompatible - you can't do A/B testing
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Code changes

We have changed the name of the field lastName on surname.

Renaming a column in a backward compatible way

This is the most common situation we may encounter. We need to make backward incompatible changes. We have already proven that for deployment without downtime, we should not just apply a database migration without additional steps. In this section of the article, we will perform 3 deployments of the application along with database migrations in order to achieve the desired result while maintaining backward compatibility.

The note. Recall that we have a version DB v1. It contains columns first_name и last_name. We must change last_name on surname. We also have app version 1.0.0, which is not yet used surname.

Step 2: Add surname

Application version: 2.0.0
DB version: v2

Comment

By adding a new column and copying its contents, we create backward compatible database changes. At the same time, if we roll back the JAR or have a working old JAR, it won't break at run time.

Rolling out a new version

Steps:

  1. do a database migration to create a new column surname. Now your db version v2
  2. copy data from last_name в surname. Notethat if you have a lot of this data, you should consider batch migration!
  3. write code that uses BOTH и newand old column. Now your app version 2.0.0
  4. read value from column surnameif it is not null, or from last_name, if surname not set. You can delete getLastName() from the code as it will issue null when you rollback your application with 3.0.0 to 2.0.0.

If you are using Spring Boot Flyway, these two steps will be done at release time 2.0.0 applications. If you run the database versioning tool manually, you will have to do two different steps to do this (upgrade the db version manually first, and then deploy the new application).

Important. Remember that the newly created column SHOULD NOT be NOT NULL. If you do a rollback, the old application does not know about the new column and will not set it in time Insert. But if you add this constraint and your db will be v2, this will require setting the value of the new column. Which will lead to constraint violations.

Important. You should remove the method getLastName(), because in the version 3.0.0 the concept of a column is missing in the code last_name. This means null will be set there. You can leave the method and add checks for null, but a much better solution would be to make sure that in the logic getSurname() you have chosen the correct non-null value.

A/B testing

The current situation is that we have a version application 1.0.0, deployed on the prod, and the database in v1. We have to deploy a second instance of the app version 2.0.0which will update the database to v2.

Steps:

  1. deployed a new version application instance 2.0.0which updates the database to v2
  2. in the meantime, some requests were handled by version instances 1.0.0
  3. the upgrade was successful and you have multiple running instances of the version app 1.0.0 and other versions 2.0.0. Everyone communicates with the DB in v2
  4. version 1.0.0 does not use the surname column in the database, but the version 2.0.0 uses. They do not interfere with each other, and there should be no errors.
  5. version 2.0.0 saves data in both the old and new column, which ensures backwards compatibility

Important. If you have any queries that count items based on values ​​from the old/new column, you should be aware that you now have duplicate values ​​(they are most likely still migrating). For example, if you want to count the number of users whose last name (whatever the name of the column) starts with a letter A, then until the data migration is completed (oldnew column) you might have inconsistent data if you are querying a new column.

Application Rollback

We now have an app version 2.0.0 and database in v2.

Steps:

  1. rollback your application to a version 1.0.0.
  2. version 1.0.0 does not use a column in the database surnameso the rollback should be successful

DB changes

The database contains a column named last_name.

Flyway source script:

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Add script surname.

Attention. Remember that you DO NOT ADD any NOT NULL constraints to the column being added. If you rollback the JAR, the old version has no idea about the added column and will automatically set it to NULL. If there is such a limitation, the old application will simply break.

-- NOTE: This field can't have the NOT NULL constraint cause if you rollback, the old version won't know about this field
-- and will always set it to NULL
ALTER TABLE PERSON ADD surname varchar(255);

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Code changes

We store data as last_nameAnd in surname. At the same time, we read from last_namebecause this column is the most relevant. During the deployment process, some requests may have been processed by an application instance that has not yet been updated.

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

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

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;
    private String surname;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    /**
     * Reading from the new column if it's set. If not the from the old one.
     *
     * When migrating from version 1.0.0 -> 2.0.0 this can lead to a possibility that some data in
     * the surname column is not up to date (during the migration process lastName could have been updated).
     * In this case one can run yet another migration script after all applications have been deployed in the
     * new version to ensure that the surname field is updated.
     *
     * However it makes sense since when looking at the migration from 2.0.0 -> 3.0.0. In 3.0.0 we no longer
     * have a notion of lastName at all - so we don't update that column. If we rollback from 3.0.0 -> 2.0.0 if we
     * would be reading from lastName, then we would have very old data (since not a single datum was inserted
     * to lastName in version 3.0.0).
     */
    public String getSurname() {
        return this.surname != null ? this.surname : this.lastName;
    }

    /**
     * Storing both FIRST_NAME and SURNAME entries
     */
    public void setSurname(String surname) {
        this.lastName = surname;
        this.surname = surname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", lastName=" + this.lastName + ", surname=" + this.surname
                + "]";
    }
}

Step 3: Removing last_name from code

Application version: 3.0.0

DB version:v3

Comment

Note. trans.: Apparently, in the original article, the author mistakenly copied the text of this block from step 2. At this step, changes should be made in the application code aimed at removing the functionality that uses the column last_name.

By adding a new column and copying its contents, we have created backward compatible database changes. Also, if we roll back the JAR or we have a working old JAR, it won't break at runtime.

Application Rollback

We currently have app version 3.0.0 and database v3. Version 3.0.0 does not store data in last_name. This means that in surname the most up-to-date information is stored.

Steps:

  1. rollback your application to a version 2.0.0.
  2. version 2.0.0 uses and last_name и surname.
  3. version 2.0.0 will take surnameif it is not null, otherwiselast_name

Database changes

There are no structural changes in the database. The following script is executed, which performs the final migration of the old data:

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
-- ALSO WE'RE NOT CHECKING IF WE'RE NOT OVERRIDING EXISTING ENTRIES. WE WOULD HAVE TO COMPARE
-- ENTRY VERSIONS TO ENSURE THAT IF THERE IS ALREADY AN ENTRY WITH A HIGHER VERSION NUMBER
-- WE WILL NOT OVERRIDE IT.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;

-- DROPPING THE NOT NULL CONSTRAINT; OTHERWISE YOU WILL TRY TO INSERT NULL VALUE OF THE LAST_NAME
-- WITH A NOT_NULL CONSTRAINT.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;

Code changes

Note. per.: The description of this block was also mistakenly copied by the author from step 2. In accordance with the logic of the article's narration, changes in the code at this step should be aimed at removing elements from it that work with the column last_name.

We store data as last_nameAnd in surname. Also, we read from the column last_namebecause it is the most relevant. During the deployment process, some requests may be processed by an instance that has not yet been upgraded.

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

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

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String surname;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getSurname() {
        return this.surname;
    }

    public void setSurname(String lastname) {
        this.surname = lastname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", surname=" + this.surname
                + "]";
    }
}

Step 4: Removing last_name from the database

Application version: 4.0.0

DB version: v4

Comment

Because the version code 3.0.0 did not use column last_name, nothing bad will happen during execution if we rollback to 3.0.0 after deleting a column from the database.

Script execution logs

We will do it in the following way:

01) Run 1.0.0
02) Wait for the app (1.0.0) to boot
03) Generate a person by calling POST localhost:9991/person to version 1.0.0
04) Run 2.0.0
05) Wait for the app (2.0.0) to boot
06) Generate a person by calling POST localhost:9991/person to version 1.0.0
07) Generate a person by calling POST localhost:9992/person to version 2.0.0
08) Kill app (1.0.0)
09) Run 3.0.0
10) Wait for the app (3.0.0) to boot
11) Generate a person by calling POST localhost:9992/person to version 2.0.0
12) Generate a person by calling POST localhost:9993/person to version 3.0.0
13) Kill app (3.0.0)
14) Run 4.0.0
15) Wait for the app (4.0.0) to boot
16) Generate a person by calling POST localhost:9993/person to version 3.0.0
17) Generate a person by calling POST localhost:9994/person to version 4.0.0

Starting app in version 1.0.0
Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

{"firstName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2","lastName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2"}

Starting app in version 2.0.0

Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

{"firstName":"e41ee756-4fa7-4737-b832-e28827a00deb","lastName":"e41ee756-4fa7-4737-b832-e28827a00deb"}

Generate a person in version 2.0.0
Sending a post to 127.0.0.1:9992/person. This is the response:

{"firstName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","lastName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","surname":"0c1240f5-649a-4bc5-8aa9-cff855f3927f"}

Killing app 1.0.0

Starting app in version 3.0.0

Generate a person in version 2.0.0
Sending a post to 127.0.0.1:9992/person. This is the response:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}

Generate a person in version 3.0.0
Sending a post to 127.0.0.1:9993/person. This is the response:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}

Killing app 2.0.0

Starting app in version 4.0.0

Generate a person in version 3.0.0
Sending a post to 127.0.0.1:9993/person. This is the response:

{"firstName":"cbe942fc-832e-45e9-a838-0fae25c10a51","surname":"cbe942fc-832e-45e9-a838-0fae25c10a51"}

Generate a person in version 4.0.0
Sending a post to 127.0.0.1:9994/person. This is the response:

{"firstName":"ff6857ce-9c41-413a-863e-358e2719bf88","surname":"ff6857ce-9c41-413a-863e-358e2719bf88"}

DB changes

About v3 we just remove the column last_name and add the missing constraints.

-- REMOVE THE COLUMN
ALTER TABLE PERSON DROP last_name;

-- ADD CONSTRAINTS
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Code changes

There are no changes in the code.

Hack and predictor Aviator

We have successfully applied the backwards incompatible column name change by doing several backwards compatible deployments. Below is a summary of the steps taken:

  1. deploy app version 1.0.0 с v1 DB schema (column name = last_name)
  2. deploy app version 2.0.0, which saves data in last_name и surname. The application reads from last_name. DB is in version v2, containing columns like last_nameAnd surname. surname is a copy of last_name. (NOTE: this column must not have a not null constraint)
  3. deploy app version 3.0.0, which only stores data in surname and reads from surname. As for the DB, the last migration takes place last_name в surname. Also the restriction NOT NULL withdrawn from last_name. DB is currently in version v3
  4. deploy app version 4.0.0 - no changes are made to the code. Database deployment v4, which removes last_name. Here you can add any missing constraints to the database.

By following this approach, you can always roll back one version without breaking database/application compatibility.

Code

All code used in this article is available at Github. Below is an additional description.

Projects

After cloning the repository, you will see the following folder structure.

├── boot-flyway-v1              - 1.0.0 version of the app with v1 of the schema
├── boot-flyway-v2              - 2.0.0 version of the app with v2 of the schema (backward-compatible - app can be rolled back)
├── boot-flyway-v2-bad          - 2.0.0.BAD version of the app with v2bad of the schema (backward-incompatible - app cannot be rolled back)
├── boot-flyway-v3              - 3.0.0 version of the app with v3 of the schema (app can be rolled back)
└── boot-flyway-v4              - 4.0.0 version of the app with v4 of the schema (app can be rolled back)

Scripts

You can run the scripts described in the scripts below, which will demonstrate backward compatible and incompatible changes to the database.

To see case with backwards compatible changes, run:

./scripts/scenario_backward_compatible.sh

And to see case of backward incompatible changes, run:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

All examples are taken from Spring Boot Sample Flyway.

You can take a look at http://localhost:8080/flyway, there is a list of scripts.

This example also includes the H2 console (at http://localhost:8080/h2-console) so that you can view the state of the database (the default jdbc URL is jdbc:h2:mem:testdb).

Additionally

Also read other articles on our blog:

Source: habr.com

Add a comment