Nulla állásidő telepítés és adatbázisok

Nulla állásidő telepítés és adatbázisok

Ez a cikk részletesen bemutatja, hogyan lehet megoldani az adatbázis-kompatibilitási problémákat a telepítés során. Elmondjuk, mi történhet éles alkalmazásaival, ha előzetes felkészülés nélkül próbálja telepíteni. Ezután végigmegyünk az alkalmazás életciklusának azon szakaszain, amelyek a nulla leálláshoz szükségesek (kb. sáv: tovább - nulla leállás). Műveleteink eredménye az lesz, hogy a visszafelé nem kompatibilis adatbázis-módosítást visszafelé kompatibilis módon alkalmazzuk.

Ha meg szeretné érteni a cikkben szereplő kódpéldákat, megtalálja őket a következő címen: GitHub.

Bevezetés

Nulla állásidő telepítés

Milyen misztikus nulla állásidő telepítés? Elmondható, hogy ilyenkor az alkalmazást úgy telepítik, hogy sikeresen be tudja vezetni az alkalmazás új verzióját a termelésbe, miközben a felhasználó nem veszi észre annak elérhetetlenségét. Felhasználói és vállalati szempontból ez a lehető legjobb telepítési forgatókönyv, mert lehetővé teszi új szolgáltatások bevezetését és a hibák kijavítását zavartalanul.

Hogyan lehet ezt elérni? Számos módja van, ezek közül az egyik:

  • telepítse szolgáltatása 1-es verzióját
  • végezzen adatbázis-áttelepítést
  • Telepítse szolgáltatása 2-es verzióját az 1-es verzióval párhuzamosan
  • amint látja, hogy a 2-es verzió megfelelően működik, távolítsa el az 1-es verziót
  • kész!

Könnyű, nem? Sajnos ez nem ilyen egyszerű, ezt majd később részletesen megvizsgáljuk. Most nézzünk meg egy másik meglehetősen gyakori telepítési folyamatot - a kék zöld telepítést.

Hallottál már róla kék zöld bevetés? A Cloud Foundry ezt rendkívül egyszerűvé teszi. Csak nézd ez a cikk, ahol ezt részletesebben leírjuk. Röviden összefoglalva emlékeztessük Önt a kék zöld telepítésre:

  • győződjön meg arról, hogy a gyártási kód két példánya („kék” és „zöld”) működik;
  • minden forgalmat a kék környezetbe irányítani, pl. hogy az éles URL-ek oda mutassanak;
  • telepítse és tesztelje az összes alkalmazásmódosítást zöld környezetben;
  • az URL-eket kékről zöldre váltja

A kékzöld üzembe helyezés egy olyan megközelítés, amely lehetővé teszi új szolgáltatások egyszerű bevezetését anélkül, hogy aggódnia kellene a termelés leállásától. Ez annak a ténynek köszönhető, hogy még ha történik is valami, könnyen visszaléphet az előző környezetbe, ha egyszerűen „megnyom egy kapcsolót”.

A fentiek elolvasása után felteheti a kérdést: Mi köze a nulla leállásnak a kék zöld telepítéshez?

Nos, elég sok közös van bennük, mivel ugyanazon környezet két példányának karbantartása dupla erőfeszítést igényel a karbantartásuk. Ezért állítják egyes csapatok Martin Fowler, kövesse ennek a megközelítésnek egy változatát:

Egy másik lehetőség ugyanazt az adatbázist használni, kék-zöld kapcsolók létrehozásával a webes és a tartományi rétegekhez. Ebben a megközelítésben az adatbázis gyakran problémát jelenthet, különösen akkor, ha módosítania kell a sémáját, hogy támogassa a szoftver új verzióját.

És itt elérkeztünk a cikk fő problémájához. Adatbázis. Vessünk még egy pillantást erre a kifejezésre.

végezzen adatbázis-áttelepítést.

Most fel kell tennie magának a kérdést: mi van akkor, ha az adatbázis-módosítás nem kompatibilis visszafelé? Nem fog elromlani az alkalmazás első verziója? Valójában pontosan ez fog történni...

Tehát még a nulla állásidő/kékzöld üzembe helyezés hatalmas előnyei ellenére is a vállalatok hajlamosak a következő biztonságosabb eljárást követni alkalmazásaik üzembe helyezésekor:

  • készítsen csomagot az alkalmazás új verziójával
  • zárjon le egy futó alkalmazást
  • futtasson parancsfájlokat az adatbázis áttelepítéséhez
  • telepítse és indítsa el az alkalmazás új verzióját

Ebben a cikkben részletezzük, hogyan dolgozhat az adatbázisával és a kóddal, hogy kihasználhassa az állásidő nélküli üzembe helyezés előnyeit.

Adatbázis problémák

Ha olyan állapot nélküli alkalmazással rendelkezik, amely nem tárol semmilyen adatot az adatbázisban, azonnali üzembe helyezést kaphat. Sajnos a legtöbb szoftvernek valahol adatokat kell tárolnia. Ez az oka annak, hogy kétszer is meg kell gondolnia, mielőtt bármilyen változtatást végrehajtana az áramkörön. Mielőtt belemennénk a séma módosításának részleteibe, hogy lehetővé váljon az állásidő nélküli üzembe helyezés, először összpontosítsunk a verziószámítási sémára.

Verziós séma

Ebben a cikkben fogjuk használni Flyway verzióvezérlő eszközként (kb. Fordítás: adatbázis migrációról beszélünk). Természetesen írunk egy Spring Boot alkalmazást is, amely beépített Flyway támogatással rendelkezik, és az alkalmazás környezetének beállítása közben sémaáttelepítést hajt végre. A Flyway használatakor a migrációs szkripteket a projektek mappájában tárolhatja (alapértelmezés szerint a classpath:db/migration). Itt láthat egy példát ilyen migrációs fájlokra

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

Ebben a példában 4 áttelepítési parancsfájlt látunk, amelyek, ha korábban nem lettek végrehajtva, az alkalmazás indításakor egymás után kerülnek végrehajtásra. Nézzük meg az egyik fájlt (V1__init.sql) mint például.

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

Minden tökéletesen magától értetődő: az SQL segítségével meghatározhatja, hogyan kell módosítani az adatbázist. A Spring Boot és a Flyway termékekről további információért tekintse meg Spring Boot Docs.

Ha forrásvezérlő eszközt használ a Spring Boot-tal, akkor 2 nagy előnyhöz jut:

  • elkülöníti az adatbázis-változásokat a kódváltozásoktól
  • Az adatbázis-migráció az alkalmazás bevezetésével együtt történik, azaz. a telepítési folyamat leegyszerűsödik

Adatbázis-problémák elhárítása

A cikk következő részében az adatbázis-módosítások két megközelítésére összpontosítunk.

  • visszamenőleges összeférhetetlenség
  • visszafelé kompatibilitás

Az első figyelmeztetésnek tekinthető, hogy előzetes felkészülés nélkül ne hajtson végre nulla leállási üzembe helyezést... A második arra kínál megoldást, hogy hogyan lehet leállás nélkül végrehajtani a telepítést, és egyben megőrizni a visszamenőleges kompatibilitást.

Projektünk, amelyen dolgozunk, egy egyszerű Spring Boot Flyway alkalmazás lesz, amely rendelkezik Person с first_name и last_name az adatbázisban (kb. fordítás: Person egy táblázat és first_name и last_name - ezek a mezők benne). Át akarjuk nevezni last_name в surname.

Feltételezések

Mielőtt belemennénk a részletekbe, van néhány feltételezés, amit meg kell tennünk az alkalmazásainkkal kapcsolatban. A fő eredmény, amit szeretnénk elérni, egy meglehetősen egyszerű folyamat lesz.

A jegyzet. Üzleti PRO-TIP. A folyamatok egyszerűsítésével sok pénzt takaríthat meg a támogatáson (minél több ember dolgozik a cégénél, annál több pénzt takaríthat meg)!

Nincs szükség az adatbázis visszaállítására

Ez leegyszerűsíti a telepítési folyamatot (egyes adatbázis-visszaállítások szinte lehetetlenek, például a törlés visszagörgetése). Inkább csak az alkalmazásokat vonjuk vissza. Így még akkor is, ha különböző adatbázisai vannak (például SQL és NoSQL), a telepítési folyamat ugyanúgy fog kinézni.

MINDIG lehetővé kell tenni az alkalmazás egy verziójának visszaállítását (nem többet)

A visszaállítást csak szükség esetén szabad elvégezni. Ha a jelenlegi verzióban olyan hiba van, amelyet nem könnyű kijavítani, akkor vissza kell tudnunk állni a legújabb működő verzióra. Feltételezzük, hogy ez a legújabb működő verzió az előző. A kód- és adatbázis-kompatibilitás fenntartása egynél több kiadásnál rendkívül nehéz és költséges lenne.

A jegyzet. A jobb olvashatóság érdekében ebben a cikkben megváltoztatjuk az alkalmazás fő verzióját.

1. lépés: Kezdeti állapot

App verzió: 1.0.0
DB verzió: v1

Megjegyzés

Ez lesz az alkalmazás kezdeti állapota.

Adatbázis változások

A DB tartalmaz 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');

Kódmódosítások

Az alkalmazás a Személyes adatokat tárolja 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
                + "]";
    }
}

Visszafelé nem kompatibilis oszlop átnevezés

Nézzünk egy példát egy oszlopnév megváltoztatására:

Figyelem. A következő példa szándékosan összetöri a dolgokat. Ezt az adatbázis-kompatibilitás problémájának bemutatására mutatjuk be.

App verzió: 2.0.0.BAD

DB verzió: v2bad

Megjegyzés

A jelenlegi változtatások NEM engedik meg, hogy egyszerre két példányt (régi és új) futtassunk. Így a nulla állásidő-kiépítést nehéz lesz elérni (ha figyelembe vesszük a feltételezéseket, ez valójában lehetetlen).

A/B tesztelés

A jelenlegi helyzet az, hogy van egy alkalmazás verziónk 1.0.0, üzembe helyezve a termelésben és az adatbázisban v1. Telepítenünk kell az alkalmazás második példányát, a verziót 2.0.0.BAD, és frissítse az adatbázist erre v2bad.

Lépések:

  1. a verzióalkalmazás új példánya kerül telepítésre 2.0.0.BADamelyre frissíti az adatbázist v2bad
  2. az adatbázisban v2bad oszlop last_name már nem létezik – erre módosult surname
  3. Az adatbázis és az alkalmazás frissítése sikeres volt, és néhány példány fut 1.0.0, mások - be 2.0.0.BAD. Minden az adatbázishoz kapcsolódik v2bad
  4. verzió összes példánya 1.0.0 hibákat fog dobni, mert megpróbálnak adatokat beszúrni az oszlopba last_nameaki már nem létezik
  5. verzió összes példánya 2.0.0.BAD probléma nélkül fog működni

Mint látható, ha visszafelé inkompatibilis változtatásokat végzünk az adatbázisban és az alkalmazásban, az A/B tesztelés lehetetlen.

Alkalmazás visszaállítása

Tegyük fel, hogy miután megpróbáltuk végrehajtani az A/B telepítést (kb. per.: itt valószínűleg A/B tesztelésre gondolt a szerző) úgy döntöttünk, hogy vissza kell állítanunk az alkalmazást a verzióra 1.0.0. Tegyük fel, hogy nem akarjuk visszaállítani az adatbázist.

Lépések:

  1. leállítjuk a verziójú alkalmazáspéldányt 2.0.0.BAD
  2. az adatbázis még mindig v2bad
  3. verzió óta 1.0.0 nem érti mi az surname, látni fogjuk a hibákat
  4. elszabadult a pokol, már nem mehetünk vissza

Mint látható, ha visszafelé inkompatibilis változtatásokat végzünk az adatbázisban és az alkalmazásban, akkor nem tudunk visszalépni az előző verzióra.

Parancsfájl-végrehajtási naplók

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

Adatbázis változások

Migrációs szkript, amely átnevezi last_name в surname

A Flyway forgatókönyvének forrása:

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

Szkript, amely átnevez last_name.

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

Kódmódosítások

Módosítottuk a mező nevét lastName on surname.

Oszlop átnevezése visszafelé kompatibilis módon

Ez a leggyakoribb helyzet, amellyel találkozhatunk. Visszafelé összeférhetetlen változtatásokat kell végrehajtanunk. Már bebizonyítottuk, hogy a nulla leállási idejű telepítéshez nem szabad egyszerűen adatbázis-migrációt alkalmazni további lépések nélkül. A cikknek ebben a részében az alkalmazás 3 központi telepítését hajtjuk végre az adatbázis-áttelepítésekkel együtt, hogy elérjük a kívánt eredményt, miközben megőrizzük a visszamenőleges kompatibilitást.

A jegyzet. Emlékezzünk vissza, hogy van egy verzió adatbázisunk v1. Oszlopokat tartalmaz first_name и last_name. Változnunk kell last_name on surname. Van app verziónk is 1.0.0, amelyet még nem használnak surname.

2. lépés: Adjon hozzá vezetéknevet

App verzió: 2.0.0
DB verzió: v2

Megjegyzés

Új oszlop hozzáadásával és tartalmának másolásával visszafelé kompatibilis adatbázismódosításokat hozunk létre. Ugyanakkor, ha visszaállítjuk a JAR-t, vagy fut egy régi JAR, akkor az nem fog tönkremenni a végrehajtás során.

Új verziót vezetünk be

Lépések:

  1. végezzen adatbázis-áttelepítést egy új oszlop létrehozásához surname. Most a DB verziód v2
  2. adatok másolása innen last_name в surname. Figyeljen odahogy ha sok ilyen adattal rendelkezik, fontolja meg a kötegelt migrációt!
  3. írja be a kódot, ahol használják MINDKÉT и újÉs régi oszlop. Most az alkalmazás verziója 2.0.0
  4. olvassa ki az értéket az oszlopból surname, ha nem null, vagy last_name, ha surname nem meghatározott. Lehet törölni getLastName() a kódból, mivel kiadja null amikor visszaállítja az alkalmazást innen 3.0.0 a 2.0.0.

Ha Spring Boot Flyway-t használ, ezt a két lépést a verzió indításakor hajtja végre 2.0.0 alkalmazások. Ha manuálisan futtatja az adatbázis-verziókészítő eszközt, akkor ehhez két különböző dolgot kell tennie (először kézzel kell frissítenie a db verziót, majd telepítenie kell az új alkalmazást).

Fontos. Ne feledje, hogy az újonnan létrehozott oszlop NEM KELLENE lehet NEM NULLA. Ha visszagörgetést hajt végre, a régi alkalmazás nem tud az új oszlopról, és közben nem is telepíti Insert. De ha hozzáadja ezt a megszorítást, és a db lesz v2, ehhez be kell állítani az új oszlop értékét. Ami a korlátozások megsértéséhez vezet.

Fontos. El kell távolítani a módszert getLastName(), mert a változatban 3.0.0 A kódban nincs oszlop fogalma last_name. Ez azt jelenti, hogy itt null lesz beállítva. Kihagyhatja a módszert, és hozzáadhat ellenőrzéseket null, de sokkal jobb megoldás az lenne, ha ezt a logikában megbizonyosodnánk getSurname() helyes, nullától eltérő értéket választotta ki.

A/B tesztelés

A jelenlegi helyzet az, hogy van egy alkalmazás verziónk 1.0.0, éles környezetben, és az adatbázisban v1. Telepítenünk kell a verzióalkalmazás második példányát 2.0.0amely frissíti az adatbázist v2.

Lépések:

  1. a verzióalkalmazás új példánya kerül telepítésre 2.0.0amelyre frissíti az adatbázist v2
  2. időközben egyes kéréseket verziópéldányok dolgoztak fel 1.0.0
  3. a frissítés sikeres volt, és a verzióalkalmazás több példánya is fut 1.0.0 és más verziók 2.0.0. Mindenki kommunikál az adatbázissal v2
  4. változat 1.0.0 nem a vezetéknév oszlopot használja az adatbázisban, hanem a verziót 2.0.0 használ. Nem zavarják egymást, és nem lehetnek hibák.
  5. változat 2.0.0 a régi és az új oszlopban is tárolja az adatokat, biztosítva a visszafelé kompatibilitást

Fontos. Ha olyan lekérdezései vannak, amelyek a régi/új oszlop értékei alapján számolják az elemeket, ne feledje, hogy most ismétlődő értékek vannak (valószínűleg még mindig migrálnak). Például, ha meg akarja számolni azoknak a felhasználóknak a számát, akiknek vezetékneve (bárhogy is hívják az oszlopot) betűvel kezdődött A, majd amíg az adatmigráció be nem fejeződik (oldnew oszlop) következetlen adatokkal rendelkezhet, ha új oszlopot kérdez le.

Alkalmazás visszaállítása

Most megvan az alkalmazás verziója 2.0.0 és az adatbázisban v2.

Lépések:

  1. állítsa vissza az alkalmazást a verzióra 1.0.0.
  2. változat 1.0.0 nem használ oszlopot az adatbázisban surname, tehát a visszaállításnak sikeresnek kell lennie

DB változások

Az adatbázis egy nevű oszlopot tartalmaz last_name.

Flyway forrásszkript:

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

Szkript hozzáadása surname.

Figyelem. Ne feledje, hogy a hozzáadni kívánt oszlophoz NEM LEHET NOT NULL korlátozást hozzáadni. Ha visszaállítja a JAR-t, a régi verziónak fogalma sincs a hozzáadott oszlopról, és automatikusan NULL-ra állítja. Ha van ilyen korlátozás, a régi alkalmazás egyszerűen tönkremegy.

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

Kódmódosítások

Az adatokat mint last_nameés be surname. Ugyanakkor olvasunk a last_name, mivel ez az oszlop a legrelevánsabb. A telepítési folyamat során előfordulhat, hogy egyes kéréseket még nem frissített alkalmazáspéldány dolgozott fel.

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

3. lépés: A vezetéknév eltávolítása a kódból

App verzió: 3.0.0

DB verzió:v3

Megjegyzés

jegyzet per.: Úgy tűnik, az eredeti cikkben a szerző tévedésből másolta ki ennek a blokknak a szövegét a 2. lépésből. Ennél a lépésnél módosítani kell az alkalmazás kódját az oszlopot használó funkciók eltávolítása érdekében. last_name.

Új oszlop hozzáadásával és tartalmának másolásával visszafelé kompatibilis adatbázismódosításokat hoztunk létre. Továbbá, ha visszaállítjuk a JAR-t, vagy egy régi JAR fut, akkor az nem fog törni a végrehajtás során.

Alkalmazás visszaállítása

Jelenleg az alkalmazás verziója van 3.0.0 és adatbázis v3. Változat 3.0.0 nem menti az adatokat last_name. Ez azt jelenti, hogy be surname a legfrissebb információkat tárolják.

Lépések:

  1. állítsa vissza az alkalmazást a verzióra 2.0.0.
  2. változat 2.0.0 használ és last_name и surname.
  3. változat 2.0.0 fog tartani surname, ha nem nulla, egyébként -last_name

Adatbázis változások

Az adatbázisban nincs szerkezeti változás. A következő szkript fut le a régi adatok végső áttelepítéséhez:

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

Kódmódosítások

jegyzet per.: Ennek a blokknak a leírását is tévedésből másolta ki a szerző a 2. lépésből. A cikk logikájának megfelelően a kód ezen lépésében történő módosításainak célja az oszloppal működő elemek eltávolítása. last_name.

Az adatokat mint last_nameés be surname. Ezenkívül olvasunk a rovatból last_name, mivel ez a legrelevánsabb. A telepítési folyamat során egyes kéréseket olyan példány is feldolgozhat, amelyet még nem frissítettek.

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

4. lépés: A vezetéknév eltávolítása az adatbázisból

App verzió: 4.0.0

DB verzió: v4

Megjegyzés

Annak a ténynek köszönhetően, hogy a verziókód 3.0.0 nem használta az oszlopot last_name, semmi rossz nem fog történni a végrehajtás során, ha visszakanyarodunk 3.0.0 miután eltávolított egy oszlopot az adatbázisból.

Parancsfájl-végrehajtási naplók

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 változások

Viszonylag v3 csak eltávolítjuk az oszlopot last_name és adjon hozzá hiányzó korlátozásokat.

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

Kódmódosítások

A kódban nincs változás.

Teljesítmény

Sikeresen alkalmaztuk a visszafelé nem kompatibilis oszlopnév-módosítást több visszafelé kompatibilis központi telepítés végrehajtásával. Az alábbiakban összefoglaljuk az elvégzett műveleteket:

  1. alkalmazás verziójának telepítése 1.0.0 с v1 adatbázisséma (oszlop neve = last_name)
  2. alkalmazás verziójának telepítése 2.0.0, amely az adatokat tárolja last_name и surname. Az alkalmazás innen olvasható last_name. Az adatbázis verzióban van v2hasonló oszlopokat tartalmaz last_nameÉs surname. surname másolata az last_name. (MEGJEGYZÉS: Ebben az oszlopban nem lehet nulla megszorítás)
  3. alkalmazás verziójának telepítése 3.0.0, amely csak az adatokat tárolja surname és vezetéknévből olvas. Ami az adatbázist illeti, az utolsó migráció zajlik last_name в surname. Szintén korlátozás NEM NULLA kivonva last_name. Az adatbázis most verzióban van v3
  4. alkalmazás verziójának telepítése 4.0.0 - nem történik változás a kódon. Adatbázis telepítése v4, amely eltávolítja last_name. Itt adhatja hozzá a hiányzó kényszereket az adatbázishoz.

Ennek a megközelítésnek a követésével mindig visszaállíthat egy verziót anélkül, hogy megszakítaná az adatbázis/alkalmazás kompatibilitást.

Kód

A cikkben használt összes kód elérhető a következő címen: GitHub. Az alábbiakban további leírás található.

Projektek

A tár klónozása után a következő mappaszerkezetet fogja látni.

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

Szkriptek

Futtathatja az alábbi szkriptekben leírt szkripteket, amelyek bemutatják az adatbázis visszafelé kompatibilis és inkompatibilis módosításait.

Látni visszafelé kompatibilis változtatásokkal, fuss:

./scripts/scenario_backward_compatible.sh

És látni eset visszafelé inkompatibilis változtatásokkal, fuss:

./scripts/scenario_backward_incompatible.sh

Spring Boot Minta Flyway

Minden példa innen származik Spring Boot Sample Flyway.

Meg lehet nézni http://localhost:8080/flyway, ott van a szkriptek listája.

Ez a példa a H2 konzolt is tartalmazza (at http://localhost:8080/h2-console), így megtekintheti az adatbázis állapotát (az alapértelmezett jdbc URL jdbc:h2:mem:testdb).

emellett

Olvassa el blogunk további cikkeit is:

Forrás: will.com

Hozzászólás