Zero Downtime Deployment an Datenbanken

Zero Downtime Deployment an Datenbanken

Dësen Artikel erkläert am Detail wéi d'Datebankkompatibilitéitsprobleemer beim Deployment léisen. Mir soen Iech wat mat Äre Produktiounsapplikatioune ka geschéien wann Dir probéiert ouni virleefeg Virbereedung z'installéieren. Mir ginn dann duerch d'Uwendungsliewenszyklusstadien déi noutwenneg sinn fir null Ausdauer ze hunn (ca. Lane: weider - null Ausdauer). D'Resultat vun eisen Operatiounen wäert sinn d'Réck-inkompatibel Datebank änneren op eng zréck-kompatibel Manéier ëmzesetzen.

Wann Dir de Code Beispiller aus dem Artikel wëllt verstoen, kënnt Dir se op GitHub.

Aféierung

Null Downtime Deployment

Wat eng mystesch null Ënnerbriechung? Dir kënnt soen dat ass wann Är Applikatioun esou agesat gëtt datt Dir erfollegräich eng nei Versioun vun der Applikatioun an d'Produktioun aféiere kënnt, während de Benotzer seng Onverfügbarkeet net bemierkt. Aus enger Benotzer- a Firmenperspektiv ass dëst dee beschtméigleche Deployment Szenario well et erlaabt nei Features agefouert ze ginn an Bugs ouni Ënnerbriechung ze fixéieren.

Wéi dëst z'erreechen? Et gi verschidde Weeër, hei ass ee vun hinnen:

  • deploy Versioun Nr 1 vun Ärem Service
  • eng Datebankmigratioun ausféieren
  • Deploy Versioun #2 vun Ärem Service parallel mat Versioun #1
  • soubal Dir gesitt datt d'Versioun Nummer 2 funktionnéiert wéi se soll, huelt d'Versioun Nummer 1 ewech
  • gemaach!

Einfach, ass et net? Leider ass et net sou einfach, a mir wäerten dat spéider am Detail kucken. Loosst eis elo en aneren zimlech allgemengen Deploymentprozess iwwerpréiwen - blo gréng Deployment.

Hutt Dir jeemools héieren blo gréng Détachement? Cloud Foundry mécht dëst extrem einfach. Kuckt just un dësen Artikel, wou mir dat méi am Detail beschreiwen. Fir kuerz ze resuméieren, loosst eis Iech drun erënneren wéi Dir blo gréng Deployment maacht:

  • sécherstellen datt zwee Exemplare vun Ärem Produktiounscode ("blo" a "gréng") funktionnéieren;
  • all Verkéier an déi blo Ëmwelt riichten, d.h. sou datt d'Produktioun URLen dohinner weisen;
  • deployéieren an testen all Applikatioun Ännerungen an engem gréngen Ëmfeld;
  • schalt URLen aus blo op gréng Ëmwelt

Blo gréng Deployment ass eng Approche déi Iech erlaabt nei Features einfach z'informéieren ouni Iech Suergen iwwer d'Produktioun ze briechen. Dëst ass wéinst der Tatsaach datt och wann eppes geschitt, Dir kënnt einfach zréck an dat viregt Ëmfeld zréckrollen andeems Dir einfach "e Schalter fléisst."

Nodeems Dir all déi uewe gelies hutt, kënnt Dir d'Fro stellen: Wat huet Null Downtime mat Blue Green Deployment ze dinn?

Gutt, si hunn zimmlech vill gemeinsam, well zwee Exemplare vum selwechten Ëmfeld erhalen, erfuerdert duebel Effort fir se z'erhalen. Dofir behaapten e puer Equippen Martin Fowler, befollegt eng Variatioun vun dëser Approche:

Eng aner Optioun ass déi selwecht Datebank ze benotzen, blo-gréng Schalter fir de Web an Domain Schichten ze kreéieren. An dëser Approche kann d'Datebank dacks e Problem sinn, besonnesch wann Dir säi Schema änneren musst fir eng nei Versioun vun der Software z'ënnerstëtzen.

An hei komme mer zum Haaptproblem an dësem Artikel. Datebank. Loosst eis dëse Saz nach eng Kéier kucken.

eng Datebankmigratioun ausféieren.

Elo musst Dir Iech d'Fro stellen - wat wann d'Datebankännerung net zréckkompatibel ass? Wäert meng éischt Versioun vun der App net briechen? Tatsächlech ass dat genau wat wäert geschéien ...

Also, och trotz de grousse Virdeeler vun Null Downtime / Blogréng Deployment, tendéieren Firmen de folgende méi séchere Prozess fir hir Uwendungen z'installéieren:

  • preparéieren e Pak mat enger neier Versioun vun der Applikatioun
  • eng lafend Applikatioun zoumaachen
  • Scripte lafen fir d'Datebank ze migréieren
  • deployéieren an eng nei Versioun vun der Applikatioun starten

An dësem Artikel wäerte mir detailléiert wéi Dir mat Ärer Datebank a Code schaffe kënnt fir vun Null Downtime Deployment ze profitéieren.

Datebank Problemer

Wann Dir eng stateless Applikatioun hutt, déi keng Daten an der Datebank späichert, kënnt Dir direkt Null-Downtime-Deployment kréien. Leider muss déi meescht Software Daten iergendwou späicheren. Dofir sollt Dir zweemol nodenken ier Dir Ännerungen am Circuit maacht. Ier mer an d'Detailer kommen wéi een de Schema ännert, sou datt d'Deployment ouni Downtime méiglech ass, loosst eis fir d'éischt op de Versiounsschema konzentréieren.

Versioun Schema

An dësem Artikel wäerte mir benotzen Fluchwee als Versiounskontrollinstrument (ca. Iwwersetzung: mir schwätzen iwwer Datebankmigratiounen). Natierlech wäerte mir och eng Spring Boot Applikatioun schreiwen déi agebaute Flyway Support huet a Schema Migratioun ausféiert wärend den Applikatiounskontext opstellt. Wann Dir Flyway benotzt, kënnt Dir Migratiounsskripter an Ärem Projeten Dossier späicheren (par défaut an classpath:db/migration). Hei kënnt Dir e Beispill vun esou Migratioun Fichieren gesinn

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

An dësem Beispill gesi mir 4 Migratiounsskripter déi, wann net virdru ausgefouert goufen, een nom aneren ausgefouert ginn wann d'Applikatioun ufänkt. Loosst eis ee vun de Fichieren kucken (V1__init.sql) als Beispill.

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');

Alles ass perfekt selbstänneg: Dir kënnt SQL benotze fir ze definéieren wéi Är Datebank geännert soll ginn. Fir méi Informatiounen iwwert Fréijoer Boot an Flyway, kontrolléieren aus Fréijoer Boot Docs.

Andeems Dir e Quellkontrollinstrument mat Spring Boot benotzt, kritt Dir 2 grouss Virdeeler:

  • Dir trennt Datebank Ännerungen aus Code Ännerungen
  • Datebank Migratioun geschitt zesumme mat der Ausrollung vun Ärer Applikatioun, d.h. Ären Ofbauprozess ass vereinfacht

Troubleshooting Datebank Problemer

An der nächster Sektioun vum Artikel konzentréiere mir eis op zwou Approche fir Datebank Ännerungen ze kucken.

  • réckgängeg Inkompatibilitéit
  • Réckkompatibilitéit

Déi éischt gëtt als Warnung ugesinn datt Dir keng Null-Downtime-Deployment ouni virleefeg Virbereedung sollt maachen ... Déi zweet bitt eng Léisung fir wéi Dir en Deployment ouni Downtime ausféiere kënnt a gläichzäiteg Réckkompatibilitéit erhalen.

Eise Projet un deem mir wäerte schaffen ass eng einfach Spring Boot Flyway Applikatioun déi huet Person с first_name и last_name an der Datebank (ca. Iwwersetzung: Person ass en Dësch a first_name и last_name - dat sinn d'Felder dran). Mir wëllen ëmbenennen last_name в surname.

Viraussetzungen

Ier mer an d'Detailer kommen, ginn et e puer Viraussetzungen déi mir iwwer eis Uwendungen maache mussen. Den Haaptresultat, dee mir erreechen wëllen, ass e relativ einfache Prozess.

D'Notiz. Business PRO-TIP. Vereinfachung vu Prozesser kann Iech vill Suen op Ënnerstëtzung spueren (wat méi Leit Dir fir Är Firma schafft, wat Dir méi Sue kënnt spueren)!

Kee Grond fir d'Datebank zréckzekréien

Dëst vereinfacht den Détachement Prozess (e puer Datebank Rollbacks si bal onméiglech, wéi Läschen Rollback). Mir léiwer nëmmen Uwendungen zréckrollen. Op dës Manéier, och wann Dir verschidden Datenbanken hutt (zum Beispill SQL an NoSQL), wäert Är Deployment Pipeline d'selwecht ausgesinn.

Et muss ËMMER méiglech sinn d'Applikatioun eng Versioun zréck ze rulléieren (net méi)

Rollback soll nëmme gemaach ginn wann néideg. Wann et e Feeler an der aktueller Versioun ass, deen net einfach fixéiert ass, sollte mir fäeg sinn op déi lescht funktionnéiert Versioun zréckzekommen. Mir huelen un datt dës lescht funktionnéiert Versioun déi virdrun ass. Code an Datebank Kompatibilitéit erhalen fir méi wéi ee Rollout wier extrem schwéier an deier.

D'Notiz. Fir méi Liesbarkeet, wäerte mir an dësem Artikel d'Haaptversioun vun der Applikatioun änneren.

Schrëtt 1: Ufank Staat

App Versioun: 1.0.0
DB Versioun: v1

Commentaire

Dëst wäert den initialen Zoustand vun der Applikatioun sinn.

Datebank Ännerungen

DB enthält 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 Ännerungen

D'Applikatioun späichert Persoundaten an 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
                + "]";
    }
}

Zeréck inkompatibel Kolonn ëmbenennen

Loosst eis e Beispill kucken wéi Dir e Kolonnnumm ännert:

Opgepasst. Dat folgend Beispill wäert d'Saache bewosst briechen. Mir weisen dëst fir de Problem vun der Datebankkompatibilitéit ze weisen.

App Versioun: 2.0.0.BAD

DB Versioun: v2bad

Commentaire

Déi aktuell Ännerungen erlaben eis NET zwou Instanzen (al an nei) zur selwechter Zäit ze lafen. Also, Null Downtime Deployment wäert schwéier z'erreechen (wann Viraussetzunge berücksichtegt ginn, ass et tatsächlech onméiglech).

A/B Test

Déi aktuell Situatioun ass datt mir eng Applikatioun Versioun hunn 1.0.0, an der Produktioun agesat, an Datebank v1. Mir mussen eng zweet Instanz vun der Applikatioun ofsetzen, Versioun 2.0.0.BAD, an update der Datebank op v2bad.

Schrëtt:

  1. eng nei Instanz vun der Versiounsapplikatioun gëtt ofgesat 2.0.0.BADdéi d'Datebank aktualiséiert v2bad
  2. an der Datebank v2bad Kolonn last_name existéiert net méi - et gouf geännert surname
  3. D'Datebank an d'Applikatioun Update war erfollegräich an e puer Instanzen lafen 1.0.0, anerer - an 2.0.0.BAD. Alles ass mat der Datebank verbonnen v2bad
  4. all Instanzen vun der Versioun 1.0.0 wäert ufänken Feeler ze geheien well se probéieren Daten an d'Kolonn ze setzen last_namedéi et net méi gëtt
  5. all Instanzen vun der Versioun 2.0.0.BAD wäert ouni Problemer schaffen

Wéi Dir gesitt, wa mir réckgängeg inkompatibel Ännerungen un der Datebank an der Applikatioun maachen, ass A/B Testen onméiglech.

Applikatioun Réckroll

Loosst eis unhuelen datt nodeems Dir probéiert A/B Deployment ze maachen (ca. per .: den Auteur gemengt wahrscheinlech A / B Testen hei) hu mir décidéiert datt mir d'Applikatioun op d'Versioun mussen zréckrollen 1.0.0. Loosst eis soen datt mir d'Datebank net wëllen zréckrollen.

Schrëtt:

  1. mir stoppen der Versioun Applikatioun Instanz 2.0.0.BAD
  2. d'Datebank ass nach ëmmer v2bad
  3. zanter der Versioun 1.0.0 versteet net wat et ass surname, mir wäerte Feeler gesinn
  4. D'Häll ass gebrach, mir kënnen net méi zréck

Wéi Dir gesitt, wa mir réckgängeg inkompatibel Ännerunge vun der Datebank an der Applikatioun maachen, kënne mir net op déi viregt Versioun zréckrollen.

Skript Ausféierung Logbicher

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"}

Datebank Ännerungen

Migratiounsskript dat ëmbenannt last_name в surname

Source Flyway Skript:

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');

Skript dat ëmbenannt last_name.

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

Code Ännerungen

Mir hunn den Numm vum Feld geännert lastName op surname.

Eng Kolonn ëmbenennen op eng zréckkompatibel Manéier

Dëst ass déi heefegst Situatioun déi mir begéinen. Mir mussen réckgängeg inkompatibel Ännerungen maachen. Mir hu scho bewisen datt fir Null-Downtime Deployment, mir sollten net einfach Datebankmigratioun ouni zousätzlech Schrëtt applizéieren. An dëser Rubrik vum Artikel wäerte mir 3 Deployementer vun der Applikatioun zesumme mat Datebankmigratiounen ausféieren fir dat gewënschte Resultat z'erreechen an d'Réckkompatibilitéit z'erhalen.

D'Notiz. Erënneren, datt mir eng Versioun Datebank hunn v1. Et enthält Kolonnen first_name и last_name. Mir mussen änneren last_name op surname. Mir hunn och App Versioun 1.0.0, déi nach net benotzt gëtt surname.

Schrëtt 2: Numm derbäi

App Versioun: 2.0.0
DB Versioun: v2

Commentaire

Andeems Dir eng nei Kolonn bäidréit a säin Inhalt kopéiert, kreéiere mir zréckkompatibel Datebank Ännerungen. Zur selwechter Zäit, wa mir de JAR zréckrollen oder en alen JAR lafen, brécht en net während der Ausféierung.

Mir rullen eng nei Versioun aus

Schrëtt:

  1. eng Datebankmigratioun ausféieren fir eng nei Kolonn ze kreéieren surname. Elo Är DB Versioun v2
  2. kopéieren Daten aus last_name в surname. Opgepasstdatt wann Dir vill vun dësen Donnéeën hutt, sollt Dir Batchmigratioun betruechten!
  3. schreiwen de Code wou se benotzt ginn Béid и новыйan déi al Kolonn. Elo Är App Versioun 2.0.0
  4. liesen de Wäert aus der Kolonn surname, wann et net ass nulloder aus last_name, wann a surname net uginn. Dir kënnt läschen getLastName() aus dem Code, well et gëtt erausginn null wann Dir Är Applikatioun zréckrollt 3.0.0 ze 2.0.0.

Wann Dir Spring Boot Flyway benotzt, ginn dës zwee Schrëtt während der Versioun vum Startup gemaach 2.0.0 Uwendungen. Wann Dir d'Datebankversiouns-Tool manuell leeft, musst Dir zwou verschidde Saache maachen fir dëst ze maachen (éischt d'db Versioun manuell aktualiséieren an dann déi nei Applikatioun ofsetzen).

Et ass wichteg. Erënneren, datt déi nei geschaf Kolonn SOLL NET ze sinn NET NULL. Wann Dir eng Rollback maacht, weess déi al Applikatioun net iwwer déi nei Kolonn a wäert se net während der Installatioun installéieren Insert. Awer wann Dir dës Aschränkung bäidréit an Är db wäert sinn v2, Dëst wäert erfuerderen de Wäert vun der neier Kolonn ze setzen. Wat zu Violatioune vu Restriktiounen féiert.

Et ass wichteg. Dir sollt d'Method ewechhuelen getLastName(), well an der Versioun 3.0.0 Et gëtt kee Konzept vun enger Kolonn am Code last_name. Dëst bedeit datt null do gesat gëtt. Dir kënnt d'Method verloossen a Schecken derbäi fir null, mee eng vill besser Léisung wier sécher ze stellen, datt an der Logik getSurname() Dir hutt de richtegen Net-Nullwäert gewielt.

A/B Test

Déi aktuell Situatioun ass datt mir eng Applikatioun Versioun hunn 1.0.0, op Produktioun ofgesat, an d'Datebank an v1. Mir mussen eng zweet Instanz vun der Versiounsapplikatioun ofsetzen 2.0.0déi d'Datebank aktualiséieren v2.

Schrëtt:

  1. eng nei Instanz vun der Versiounsapplikatioun gëtt ofgesat 2.0.0déi d'Datebank aktualiséiert v2
  2. an der Tëschenzäit goufen e puer Ufroe vu Versiounsinstanzen veraarbecht 1.0.0
  3. den Update war erfollegräich an Dir hutt verschidde Lafen Instanzen vun der Versiounsapplikatioun 1.0.0 an aner Versiounen 2.0.0. Jiddereen kommunizéiert mat der Datebank an v2
  4. Versioun 1.0.0 benotzt net den Numm Kolonn an der Datebank, mä d'Versioun 2.0.0 benotzt. Si stéieren net mateneen, an et sollt kee Feeler sinn.
  5. Versioun 2.0.0 späichert Daten an der aler an der neier Kolonn, a garantéiert Réckkompatibilitéit

Et ass wichteg. Wann Dir Ufroen hutt déi Elementer zielen baséiert op Wäerter aus der aler / neier Kolonn, sollt Dir drun erënneren datt Dir elo duplizéiert Wäerter hutt (wahrscheinlech si se nach ëmmer migréieren). Zum Beispill, wann Dir d'Zuel vun de Benotzer ziele wëllt, deenen hire Familljennumm (egal wéi d'Kolonn genannt gëtt) mam Buschtaf ugefaang huet A, dann bis d'Datemigratioun fäerdeg ass (oldnew Kolonn) Dir hutt vläicht inkonsistent Donnéeën wann Dir eng nei Kolonn ufrot.

Applikatioun Réckroll

Elo hu mir App Versioun 2.0.0 an Datebank an v2.

Schrëtt:

  1. rullt Är Applikatioun op d'Versioun zréck 1.0.0.
  2. Versioun 1.0.0 benotzt keng Kolonn an der Datebank surname, sou datt d'Rollback erfollegräich ass

D'Ännerung am DB

D'Datebank enthält eng Kolonn mam Numm last_name.

Flyway Quell Skript:

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');

Schreift derbäi surname.

Opgepasst. Denkt drun datt Dir NET NULL Aschränkungen op d'Kolonn bäidréit, déi Dir bäidréit. Wann Dir de JAR zréckrollt, wäert déi al Versioun keng Ahnung iwwer déi addéiert Kolonn hunn a se automatesch op NULL setzen. Wann et esou eng Begrenzung gëtt, brécht déi al Applikatioun einfach.

-- 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 Ännerungen

Mir späicheren Daten als last_name, a surname. Gläichzäiteg liesen mir aus last_name, well dës Kolonn déi relevantst ass. Wärend dem Détachementprozess kënnen e puer Ufroe vun enger Applikatiounsinstanz veraarbecht ginn, déi nach net aktualiséiert gouf.

/*
 * 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
                + "]";
    }
}

Schrëtt 3: Last_name aus dem Code läschen

App Versioun: 3.0.0

DB Versioun:v3

Commentaire

Note per.: Scheinbar, am Originalartikel huet den Auteur falsch den Text vun dësem Block vum Schrëtt kopéiert 2. Op dësem Schrëtt sollten Ännerungen am Applikatiounscode gemaach ginn, fir d'Funktionalitéit ze läschen, déi d'Kolonn benotzt. last_name.

Andeems Dir eng nei Kolonn bäidréit a säin Inhalt kopéiert, hu mir réckgängeg kompatibel Datebank Ännerungen erstallt. Och wa mir de JAR zréckrollen oder en alen JAR lafen, brécht et net während der Ausféierung.

Applikatioun Réckroll

Momentan hu mir App Versioun 3.0.0 an Datebank v3. Versioun 3.0.0 späichert net Daten un last_name. Dat heescht, datt am surname déi aktuellst Informatioun gëtt gespäichert.

Schrëtt:

  1. rullt Är Applikatioun op d'Versioun zréck 2.0.0.
  2. Versioun 2.0.0 benotzt an last_name и surname.
  3. Versioun 2.0.0 wäert huelen surname, wann et net null ass, soss -last_name

Datebank Ännerungen

Et gi keng strukturell Ännerungen an der Datebank. De folgende Skript gëtt ausgefouert fir déi lescht Migratioun vun den alen Donnéeën auszeféieren:

-- 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 Ännerungen

Note per .: D'Beschreiwung vun dësem Block gouf och falsch vum Auteur vum Schrëtt kopéiert 2. Am Aklang mat der Logik vum Artikel, Ännerunge vum Code an dësem Schrëtt solle zielt fir Elementer ze läschen déi mat der Kolonn funktionnéieren last_name.

Mir späicheren Daten als last_name, a surname. Zousätzlech liesen mir aus der Kolonn last_name, well et am meeschte relevant ass. Wärend dem Détachementprozess kënnen e puer Ufroe vun enger Instanz veraarbecht ginn, déi nach net aktualiséiert gouf.

/*
 * 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
                + "]";
    }
}

Schrëtt 4: Last_name aus der Datebank erofhuelen

App Versioun: 4.0.0

DB Versioun: v4

Commentaire

Wéinst der Tatsaach, datt d'Versioun Code 3.0.0 hunn d'Kolonn net benotzt last_name, näischt Schlechtes wäert während der Ausféierung geschéien wa mir zréck op 3.0.0 nodeems Dir eng Kolonn aus der Datebank ewechgeholl huet.

Skript Ausféierung Logbicher

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"}

D'Ännerung am DB

Relativ v3 mir läschen just d'Kolonn last_name an dobäi vermësst Restriktiounen.

-- 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 Ännerungen

Et gi keng Ännerungen un de Code.

Konklusioun

Mir hunn erfollegräich e Réck-inkompatibel Spaltennumm Ännerung applizéiert andeems mir e puer zréckkompatibel Deployementer ausféieren. Drënner ass e Resumé vun den Aktiounen déi gemaach goufen:

  1. Détachement vun der Applikatioun Versioun 1.0.0 с v1 Datebank Schema (Kolonnnumm = last_name)
  2. Détachement vun der Applikatioun Versioun 2.0.0, déi Daten späichert an last_name и surname. D'Applikatioun liest aus last_name. D'Datebank ass an der Versioun v2enthält Spalten wéi last_namean surname. surname ass eng Kopie vum last_name. (OPGEPASST: Dës Kolonn däerf keng net null Constraint hunn)
  3. Détachement vun der Applikatioun Versioun 3.0.0, déi nëmmen Daten späichert an surname a liest aus Familljennumm. Wat d'Datebank ugeet, fënnt déi lescht Migratioun statt last_name в surname. Och eng Begrenzung NET NULL zréckgezunn aus last_name. D'Datebank ass elo an der Versioun v3
  4. Détachement vun der Applikatioun Versioun 4.0.0 - keng Ännerungen am Code gemaach. Datebank Deployment v4, déi läscht last_name. Hei kënnt Dir all fehlend Aschränkungen an d'Datebank derbäisetzen.

Andeems Dir dës Approche verfollegt, kënnt Dir ëmmer eng Versioun zréckrollen ouni d'Datebank-/Uwendungskompatibilitéit ze briechen.

Code

All Code an dësem Artikel benotzt ass sinn op Github. Drënner ass eng zousätzlech Beschreiwung.

Projeten

Nodeems Dir de Repository klonen, gesitt Dir déi folgend Dossierstruktur.

├── 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)

Scripten

Dir kënnt d'Skripte lafen, déi an de Scripten hei ënnen beschriwwe ginn, déi zréckkompatibel an inkompatibel Ännerungen an der Datebank weisen.

Fir ze kucken de Fall mat Réckkompatibel Ännerungen, lafen:

./scripts/scenario_backward_compatible.sh

An ze gesinn Fall mat réckgängeg inkompatibel Ännerungen, lafen:

./scripts/scenario_backward_incompatible.sh

Fréijoer Boot Sample Flyway

All Beispiller sinn aus Spring Boot Sample Flyway.

Dir kënnt e Bléck op http://localhost:8080/flyway, et gëtt eng Lëscht vu Scripten.

Dëst Beispill enthält och d'H2 Konsol (at http://localhost:8080/h2-console) sou datt Dir den Datebankstatus kuckt (Standard jdbc URL ass jdbc:h2:mem:testdb).

Zousätzlech

Liest och aner Artikelen op eisem Blog:

Source: will.com

Setzt e Commentaire