Nulové nasadenie a databázy

Nulové nasadenie a databázy

Tento článok podrobne vysvetľuje, ako vyriešiť problémy s kompatibilitou databázy pri nasadení. Povieme vám, čo sa môže stať s vašimi produkčnými aplikáciami, ak sa pokúsite nasadiť bez predbežnej prípravy. Potom prejdeme fázami životného cyklu aplikácie, ktoré sú potrebné na nulové prestoje (približne. pruh: ďalej - nulové prestoje). Výsledkom našich operácií bude aplikovanie spätne nekompatibilnej zmeny databázy spätne kompatibilným spôsobom.

Ak chcete pochopiť príklady kódu z článku, nájdete ich na adrese GitHub.

Úvod

Nasadenie nulových prestojov

Aké mystické nasadenie nulových prestojov? Dá sa povedať, že je to vtedy, keď je vaša aplikácia nasadená tak, že môžete úspešne zaviesť novú verziu aplikácie do produkcie, pričom používateľ si nevšimne jej nedostupnosť. Z pohľadu používateľa a spoločnosti ide o najlepší možný scenár nasadenia, pretože umožňuje zaviesť nové funkcie a opraviť chyby bez prerušenia.

Ako to dosiahnuť? Existuje niekoľko spôsobov, tu je jeden z nich:

  • nasaďte verziu č. 1 vašej služby
  • vykonať migráciu databázy
  • Nasaďte verziu #2 vašej služby súbežne s verziou #1
  • akonáhle uvidíte, že verzia č. 2 funguje ako má, odstráňte verziu č. 1
  • pripravený!

Jednoduché, však? Žiaľ, nie je to také jednoduché a podrobnejšie sa na to pozrieme neskôr. Teraz sa pozrime na ďalší pomerne bežný proces nasadenia - modrozelené nasadenie.

Už ste niekedy počuli o modrá zelená nasadenie? Cloud Foundry to veľmi uľahčuje. Len sa pozrite tento článok, kde to popíšeme podrobnejšie. Aby sme to stručne zhrnuli, pripomeňme vám, ako vykonať nasadenie modrej zelenej:

  • zabezpečte, aby dve kópie vášho výrobného kódu („modrá“ a „zelená“) fungovali;
  • smerovať všetku dopravu do modrého prostredia, t.j. aby tam smerovali produkčné adresy URL;
  • nasadiť a otestovať všetky zmeny aplikácií v zelenom prostredí;
  • prepnite adresy URL z modrého na zelené prostredie

Modrozelené nasadenie je prístup, ktorý vám umožňuje jednoducho zavádzať nové funkcie bez obáv z prerušenia výroby. Dôvodom je skutočnosť, že aj keď sa niečo stane, môžete sa jednoducho vrátiť do predchádzajúceho prostredia jednoduchým „potiahnutím prepínača“.

Po prečítaní vyššie uvedeného si môžete položiť otázku: Čo má nulové prestoje spoločné s nasadením Blue green?

No, majú pomerne veľa spoločného, ​​pretože udržiavanie dvoch kópií toho istého prostredia vyžaduje dvojnásobné úsilie na ich údržbu. To je dôvod, prečo niektoré tímy tvrdia Martin Fowler, postupujte podľa variácie tohto prístupu:

Ďalšou možnosťou je použiť rovnakú databázu a vytvoriť modro-zelené prepínače pre webovú a doménovú vrstvu. V tomto prístupe môže byť databáza často problémom, najmä ak potrebujete zmeniť jej schému, aby podporovala novú verziu softvéru.

A tu sa dostávame k hlavnému problému v tomto článku. databázy. Pozrime sa na túto frázu ešte raz.

vykonať migráciu databázy.

Teraz si musíte položiť otázku – čo ak zmena databázy nie je spätne kompatibilná? Nerozbije sa moja prvá verzia aplikácie? V skutočnosti sa presne toto stane...

Takže aj napriek obrovským výhodám nulových prestojov / modrozeleného nasadenia majú spoločnosti tendenciu postupovať pri nasadzovaní svojich aplikácií nasledujúcim bezpečnejším procesom:

  • pripraviť balík s novou verziou aplikácie
  • vypnúť spustenú aplikáciu
  • spustiť skripty na migráciu databázy
  • nasadiť a spustiť novú verziu aplikácie

V tomto článku podrobne popíšeme, ako môžete pracovať s databázou a kódom, aby ste využili výhody nasadenia s nulovými prestojmi.

Problémy s databázou

Ak máte bezstavovú aplikáciu, ktorá neukladá žiadne údaje do databázy, môžete okamžite dosiahnuť nulové nasadenie. Bohužiaľ, väčšina softvéru potrebuje niekde ukladať dáta. To je dôvod, prečo by ste si mali dvakrát premyslieť, než vykonáte akékoľvek zmeny v obvode. Skôr než sa dostaneme k podrobnostiam o tom, ako zmeniť schému tak, aby nasadenie nebolo možné bez výpadkov, zamerajme sa najprv na schému verzií.

Schéma verzovania

V tomto článku použijeme Flyway ako nástroj na správu verzií (približne. Preklad: hovoríme o migrácii databáz). Prirodzene, napíšeme aj aplikáciu Spring Boot, ktorá má vstavanú podporu Flyway a bude vykonávať migráciu schém pri nastavovaní kontextu aplikácie. Pri používaní Flyway môžete ukladať migračné skripty do priečinka projektov (štandardne v classpath:db/migration). Tu môžete vidieť príklad takýchto migračných súborov

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

V tomto príklade vidíme 4 migračné skripty, ktoré, ak neboli vykonané predtým, budú spustené jeden po druhom pri spustení aplikácie. Pozrime sa na jeden zo súborov (V1__init.sql) ako príklad.

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

Všetko je dokonale samovysvetľujúce: pomocou SQL môžete definovať, ako sa má vaša databáza upraviť. Viac informácií o Spring Boot a Flyway nájdete na stránke Spring Boot Docs.

Použitím nástroja na ovládanie zdroja s aplikáciou Spring Boot získate 2 veľké výhody:

  • oddeľujete zmeny databázy od zmien kódu
  • Migrácia databázy prebieha spolu s uvedením vašej aplikácie, t.j. váš proces nasadenia je zjednodušený

Riešenie problémov s databázou

V ďalšej časti článku sa zameriame na dva prístupy k zmenám databázy.

  • spätná nekompatibilita
  • spätná kompatibilita

Prvý bude považovaný za varovanie, že by ste nemali vykonávať nasadenie s nulovým prestojom bez predbežnej prípravy... Druhý ponúka riešenie, ako môžete vykonať nasadenie bez prestojov a zároveň zachovať spätnú kompatibilitu.

Náš projekt, na ktorom budeme pracovať, bude jednoduchá aplikácia Spring Boot Flyway, ktorá má Person с first_name и last_name v databáze (približne. preklad: Person je stôl a first_name и last_name - to sú polia v ňom). Chceme sa premenovať last_name в surname.

Predpoklady

Predtým, ako sa dostaneme k detailom, musíme urobiť niekoľko predpokladov o našich aplikáciách. Hlavným výsledkom, ktorý chceme dosiahnuť, bude pomerne jednoduchý proces.

Poznámka. Podnikateľský PRO-TIP. Zjednodušenie procesov vám môže ušetriť veľa peňazí na podpore (čím viac ľudí pracuje pre vašu spoločnosť, tým viac peňazí môžete ušetriť)!

Nie je potrebné vrátiť databázu späť

To zjednodušuje proces nasadenia (niektoré vrátenie databáz je takmer nemožné, ako napríklad vrátenie zmien pri odstránení). Preferujeme vrátiť späť iba aplikácie. Týmto spôsobom, aj keď máte rozdielne databázy (napríklad SQL a NoSQL), váš kanál nasadenia bude vyzerať rovnako.

VŽDY musí byť možné vrátiť aplikáciu o jednu verziu späť (nie viac)

Vrátenie späť by sa malo vykonávať iba v prípade potreby. Ak sa v aktuálnej verzii vyskytne chyba, ktorú nie je možné ľahko opraviť, mali by sme byť schopní vrátiť sa k najnovšej pracovnej verzii. Predpokladáme, že táto najnovšia pracovná verzia je tá predchádzajúca. Udržiavanie kompatibility kódu a databáz pre viac ako jedno zavedenie by bolo mimoriadne náročné a drahé.

Poznámka. Pre väčšiu čitateľnosť v tomto článku zmeníme hlavnú verziu aplikácie.

Krok 1: Počiatočný stav

Verzia aplikácie: 1.0.0
Verzia DB: v1

Komentár

Toto bude počiatočný stav aplikácie.

Zmeny databázy

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

Zmeny kódu

Aplikácia ukladá osobné údaje 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
                + "]";
    }
}

Spätne nekompatibilné premenovanie stĺpcov

Pozrime sa na príklad, ako zmeniť názov stĺpca:

Pozor. Nasledujúci príklad veci zámerne rozbije. Ukážeme to, aby sme demonštrovali problém kompatibility databázy.

Verzia aplikácie: 2.0.0.BAD

Verzia DB: v2bad

Komentár

Aktuálne zmeny nám NEUMOŽŇUJÚ spustiť dve inštancie (starú a novú) súčasne. Nasadenie nulových prestojov teda bude ťažké dosiahnuť (ak sa vezmú do úvahy predpoklady, je to vlastne nemožné).

A/B testovanie

Aktuálna situácia je taká, že máme verziu aplikácie 1.0.0, nasadené v produkcii a databáze v1. Potrebujeme nasadiť druhú inštanciu aplikácie, verziu 2.0.0.BADa aktualizujte databázu na v2bad.

kroky:

  1. je nasadená nová inštancia verzie aplikácie 2.0.0.BADktorý aktualizuje databázu na v2bad
  2. v databáze v2bad stĺp last_name už neexistuje – bol zmenený na surname
  3. Aktualizácia databázy a aplikácie bola úspešná a niektoré inštancie sú spustené 1.0.0, iní - v 2.0.0.BAD. Všetko je prepojené s databázou v2bad
  4. všetky inštancie verzie 1.0.0 začnú vyhadzovať chyby, pretože sa pokúsia vložiť údaje do stĺpca last_namektorý už neexistuje
  5. všetky inštancie verzie 2.0.0.BAD bude fungovať bez problémov

Ako vidíte, ak vykonáme spätne nekompatibilné zmeny v databáze a aplikácii, A/B testovanie je nemožné.

Vrátenie aplikácie

Predpokladajme, že po pokuse o nasadenie A/B (približne. per.: autor tu asi myslel A/B testovanie) sme sa rozhodli, že musíme aplikáciu vrátiť späť na verziu 1.0.0. Povedzme, že nechceme vrátiť späť databázu.

kroky:

  1. zastavíme inštanciu aplikácie verzie 2.0.0.BAD
  2. databáza je stále v2bad
  3. od verzie 1.0.0 nerozumie, čo to je surname, uvidíme chyby
  4. peklo sa rozpútalo, už sa nemôžeme vrátiť

Ako vidíte, ak vykonáme spätne nekompatibilné zmeny v databáze a aplikácii, nemôžeme sa vrátiť k predchádzajúcej verzii.

Protokoly vykonávania skriptov

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

Zmeny databázy

Migračný skript, ktorý premenuje last_name в surname

Zdrojový skript Flyway:

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, ktorý sa premenuje last_name.

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

Zmeny kódu

Zmenili sme názov poľa lastName na surname.

Premenovanie stĺpca spätne kompatibilným spôsobom

Toto je najčastejšia situácia, s ktorou sa môžeme stretnúť. Musíme urobiť spätne nekompatibilné zmeny. Už sme dokázali, že pre nasadenie s nulovými prestojmi by sme nemali jednoducho aplikovať migráciu databázy bez ďalších krokov. V tejto časti článku vykonáme 3 nasadenia aplikácie spolu s migráciami databáz, aby sme dosiahli požadovaný výsledok pri zachovaní spätnej kompatibility.

Poznámka. Pripomeňme, že máme databázu verzií v1. Obsahuje stĺpce first_name и last_name. Musíme sa zmeniť last_name na surname. Máme aj verziu aplikácie 1.0.0, ktorý sa ešte nepoužíva surname.

Krok 2: Pridajte priezvisko

Verzia aplikácie: 2.0.0
Verzia DB: v2

Komentár

Pridaním nového stĺpca a skopírovaním jeho obsahu vytvoríme spätne kompatibilné zmeny databázy. Zároveň, ak vrátime späť JAR alebo máme spustený starý JAR, počas vykonávania sa nerozbije.

Spúšťame novú verziu

kroky:

  1. vykonajte migráciu databázy na vytvorenie nového stĺpca surname. Teraz vaša verzia DB v2
  2. kopírovať údaje z last_name в surname. Venujte pozornosťže ak máte veľa týchto údajov, mali by ste zvážiť dávkovú migráciu!
  3. napíšte kód tam, kde sa používajú OBOJE и novýA старый stĺpec. Teraz vaša verzia aplikácie 2.0.0
  4. prečítať hodnotu zo stĺpca surname, ak nie je null, alebo z last_nameak surname nešpecifikované. Môžete vymazať getLastName() z kódu, pretože vypíše null pri vrátení aplikácie späť z 3.0.0 na 2.0.0.

Ak používate Spring Boot Flyway, tieto dva kroky sa vykonajú počas spúšťania verzie 2.0.0 aplikácie. Ak spustíte nástroj na správu verzií databázy manuálne, budete musieť urobiť dve rôzne veci (najprv manuálne aktualizovať verziu databázy a potom nasadiť novú aplikáciu).

Je to dôležité. Nezabudnite, že novovytvorený stĺpec NEMAL BY byť NIE NULL. Ak vykonáte návrat späť, stará aplikácia o novom stĺpci nevie a počas neho ho nenainštaluje Insert. Ale ak pridáte toto obmedzenie a vaša db bude v2, bude to vyžadovať nastavenie hodnoty nového stĺpca. Čo povedie k porušovaniu obmedzení.

Je to dôležité. Mali by ste odstrániť metódu getLastName(), pretože vo verzii 3.0.0 V kóde neexistuje pojem stĺpca last_name. To znamená, že tam bude nastavená hodnota null. Môžete opustiť metódu a pridať kontroly null, ale oveľa lepším riešením by bolo uistiť sa, že v logike getSurname() vybrali ste správnu nenulovú hodnotu.

A/B testovanie

Aktuálna situácia je taká, že máme verziu aplikácie 1.0.0, nasadený v produkcii a databáza v v1. Potrebujeme nasadiť druhú inštanciu verzie aplikácie 2.0.0ktorý aktualizuje databázu na v2.

kroky:

  1. je nasadená nová inštancia verzie aplikácie 2.0.0ktorý aktualizuje databázu na v2
  2. medzitým boli niektoré požiadavky spracované inštanciami verzie 1.0.0
  3. aktualizácia bola úspešná a máte spustených viacero inštancií verzie aplikácie 1.0.0 a ďalšie verzie 2.0.0. Každý komunikuje s databázou v v2
  4. verzia 1.0.0 nepoužíva v databáze stĺpec priezvisko, ale verziu 2.0.0 používa. Navzájom sa nerušia a nemali by existovať žiadne chyby.
  5. verzia 2.0.0 ukladá údaje do starého aj nového stĺpca, čím je zabezpečená spätná kompatibilita

Je to dôležité. Ak máte nejaké dotazy, ktoré počítajú položky na základe hodnôt zo starého/nového stĺpca, mali by ste si uvedomiť, že teraz máte duplicitné hodnoty (s najväčšou pravdepodobnosťou stále migrujú). Napríklad, ak chcete spočítať počet používateľov, ktorých priezvisko (bez ohľadu na to, ako sa stĺpec volá) začínalo písmenom A, potom kým sa nedokončí migrácia údajov (oldnew stĺpec) môžete mať nekonzistentné údaje, ak zadáte dotaz na nový stĺpec.

Vrátenie aplikácie

Teraz máme verziu aplikácie 2.0.0 a databázy v v2.

kroky:

  1. vrátiť vašu aplikáciu na verziu 1.0.0.
  2. verzia 1.0.0 nepoužíva stĺpec v databáze surname, takže vrátenie by malo byť úspešné

Zmeny DB

Databáza obsahuje stĺpec s názvom last_name.

Zdrojový skript Flyway:

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

Pridať skript surname.

Pozor. Pamätajte, že do stĺpca, ktorý pridávate, NEMÔŽETE PRIDAŤ žiadne obmedzenia NOT NULL. Ak vrátite späť súbor JAR, stará verzia nebude vedieť o pridanom stĺpci a automaticky ho nastaví na hodnotu NULL. Ak existuje takéto obmedzenie, stará aplikácia sa jednoducho rozpadne.

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

Zmeny kódu

Údaje ukladáme ako last_namea v surname. Zároveň čítame od last_name, pretože tento stĺpec je najrelevantnejší. Počas procesu nasadenia môžu byť niektoré požiadavky spracované inštanciou aplikácie, ktorá ešte nebola aktualizovaná.

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

Krok 3: Odstránenie priezviska z kódu

Verzia aplikácie: 3.0.0

Verzia DB:v3

Komentár

Poznámka per.: Zrejme v pôvodnom článku autor omylom skopíroval text tohto bloku z kroku 2. V tomto kroku by mali byť vykonané zmeny v kóde aplikácie zamerané na odstránenie funkcionality, ktorá používa stĺpec last_name.

Pridaním nového stĺpca a skopírovaním jeho obsahu sme vytvorili spätne kompatibilné zmeny databázy. Tiež, ak vrátime späť JAR alebo máme spustený starý JAR, počas vykonávania sa nerozbije.

Vrátenie aplikácie

V súčasnosti máme verziu aplikácie 3.0.0 a databázy v3. Verzia 3.0.0 neukladá údaje do last_name. To znamená, že v surname sú uložené najaktuálnejšie informácie.

kroky:

  1. vrátiť vašu aplikáciu na verziu 2.0.0.
  2. verzia 2.0.0 používa a last_name и surname.
  3. verzia 2.0.0 bude trvať surname, ak nie je nula, inak -last_name

Zmeny databázy

V databáze nie sú žiadne štrukturálne zmeny. Na vykonanie konečnej migrácie starých údajov sa spustí nasledujúci skript:

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

Zmeny kódu

Poznámka per.: Aj popis tohto bloku autor omylom skopíroval z kroku 2. V súlade s logikou článku by zmeny v kóde v tomto kroku mali smerovať k tomu, aby sa z neho odstránili prvky, ktoré pracujú so stĺpcom last_name.

Údaje ukladáme ako last_namea v surname. Dodatočne čítame zo stĺpca last_name, pretože je to najrelevantnejšie. Počas procesu nasadenia môžu byť niektoré požiadavky spracované inštanciou, ktorá ešte nebola inovovaná.

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

Krok 4: Odstránenie priezviska z databázy

Verzia aplikácie: 4.0.0

Verzia DB: v4

Komentár

Vzhľadom k tomu, že kód verzie 3.0.0 stĺpec nepoužil last_name, počas vykonávania sa nič zlé nestane, ak sa vrátime späť k 3.0.0 po odstránení stĺpca z databázy.

Protokoly vykonávania skriptov

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

Zmeny DB

o v3 len odstránime stĺpec last_name a pridať chýbajúce obmedzenia.

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

Zmeny kódu

V kóde nie sú žiadne zmeny.

Výkon

Úspešne sme použili spätne nekompatibilnú zmenu názvu stĺpca vykonaním niekoľkých spätne kompatibilných nasadení. Nižšie je uvedený súhrn vykonaných akcií:

  1. nasadenie verzie aplikácie 1.0.0 с v1 schéma databázy (názov stĺpca = last_name)
  2. nasadenie verzie aplikácie 2.0.0, v ktorom sú uložené dáta last_name и surname. Aplikácia číta z last_name. Databáza je vo verzii v2obsahujúce stĺpce ako last_nameA surname. surname je kópiou last_name. (POZNÁMKA: Tento stĺpec nesmie mať obmedzenie typu nie null)
  3. nasadenie verzie aplikácie 3.0.0, ktorý ukladá iba údaje surname a číta z priezviska. Čo sa týka databázy, prebieha posledná migrácia last_name в surname. Tiež obmedzenie NIE NULL stiahnutý z last_name. Databáza je teraz vo verzii v3
  4. nasadenie verzie aplikácie 4.0.0 - v kóde nie sú vykonané žiadne zmeny. Nasadenie databázy v4, ktorý odstraňuje last_name. Tu môžete do databázy pridať akékoľvek chýbajúce obmedzenia.

Dodržaním tohto prístupu môžete vždy vrátiť jednu verziu späť bez narušenia kompatibility databázy/aplikácie.

kód

Všetok kód použitý v tomto článku je dostupný na GitHub. Nižšie je uvedený dodatočný popis.

Проекты

Po naklonovaní úložiska uvidíte nasledujúcu štruktúru priečinkov.

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

Skriptá

Môžete spustiť skripty popísané v nižšie uvedených skriptoch, ktoré ukážu spätne kompatibilné a nekompatibilné zmeny v databáze.

Vidieť puzdro so spätne kompatibilnými zmenami, spustiť:

./scripts/scenario_backward_compatible.sh

A vidieť prípad so spätne nekompatibilnými zmenami, spustiť:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Všetky príklady sú prevzaté z Spring Boot Sample Flyway.

Môžete sa pozrieť na http://localhost:8080/flyway, existuje zoznam skriptov.

Tento príklad zahŕňa aj konzolu H2 (at http://localhost:8080/h2-console), aby ste si mohli pozrieť stav databázy (predvolená adresa URL jdbc je jdbc:h2:mem:testdb).

ďalej

Prečítajte si aj ďalšie články na našom blogu:

Zdroj: hab.com

Pridať komentár