Uvajanje in baze podatkov brez izpadov

Uvajanje in baze podatkov brez izpadov

V tem članku je podrobno razloženo, kako odpraviti težave z združljivostjo baze podatkov pri uvajanju. Povedali vam bomo, kaj se lahko zgodi vašim produkcijskim aplikacijam, če jih poskušate uvesti brez predhodne priprave. Nato bomo šli skozi stopnje življenjskega cikla aplikacije, ki so potrebne za nič izpadov (pribl. pas: naprej - nič izpadov). Rezultat naših operacij bo uporaba nazaj nezdružljive spremembe baze podatkov na nazaj združljiv način.

Če želite razumeti primere kode iz članka, jih lahko najdete na GitHub.

Predstavitev

Nič izpadov uvajanja

Kakšna mistika uvajanje brez izpadov? Lahko rečemo, da je to takrat, ko je vaša aplikacija nameščena tako, da lahko uspešno uvedete novo različico aplikacije v produkcijo, pri čemer uporabnik ne opazi njene nerazpoložljivosti. Z vidika uporabnika in podjetja je to najboljši možni scenarij uvajanja, saj omogoča uvedbo novih funkcij in odpravljanje napak brez motenj.

Kako to doseči? Obstaja več načinov, tukaj je eden od njih:

  • uvesti različico št. 1 vaše storitve
  • izvedite selitev baze podatkov
  • Namestite različico št. 2 svoje storitve vzporedno z različico št. 1
  • Takoj ko vidite, da različica št. 2 deluje, kot bi morala, odstranite različico št. 1
  • pripravljen!

Enostavno, kajne? Na žalost to ni tako preprosto in to bomo podrobneje preučili kasneje. Zdaj pa preverimo še en dokaj pogost postopek uvajanja – modrozeleno uvajanje.

Ste že slišali modro zelena uvedba? Cloud Foundry to zelo olajša. Samo poglej ta članek, kjer to podrobneje opisujemo. Če na kratko povzamemo, naj vas spomnimo, kako narediti modro zeleno uvajanje:

  • zagotovite, da dve kopiji vaše proizvodne kode (»modra« in »zelena«) delujeta;
  • ves promet usmeriti v modro okolje, t.j. tako da produkcijski URL-ji kažejo tja;
  • uvesti in preizkusiti vse spremembe aplikacij v zelenem okolju;
  • preklopite URL-je iz modrega v zeleno okolje

Modro zelena uvedba je pristop, ki vam omogoča preprosto uvajanje novih funkcij, ne da bi vas skrbelo prekinitev proizvodnje. To je posledica dejstva, da se lahko, tudi če se kaj zgodi, preprosto vrnete nazaj v prejšnje okolje tako, da preprosto »potegnete stikalo«.

Ko boste prebrali vse zgoraj našteto, se boste morda vprašali: kaj ima nič izpadov skupnega z modrozeleno uvedbo?

No, imata kar nekaj skupnega, saj vzdrževanje dveh kopij istega okolja zahteva dvojni trud za njuno vzdrževanje. Zato nekatere ekipe trdijo Martin Fowler, sledite različici tega pristopa:

Druga možnost je, da uporabite isto bazo podatkov in ustvarite modro-zelena stikala za sloj spleta in domene. Pri tem pristopu lahko baza podatkov pogosto predstavlja težavo, zlasti ko morate spremeniti njeno shemo, da bo podpirala novo različico programske opreme.

In tu smo prišli do glavne težave v tem članku. Baza podatkov. Oglejmo si še enkrat ta stavek.

izvedite selitev baze podatkov.

Zdaj si morate zastaviti vprašanje – kaj pa, če sprememba baze podatkov ni združljiva za nazaj? Ali se moja prva različica aplikacije ne bo pokvarila? Pravzaprav se bo zgodilo točno to ...

Torej, kljub ogromnim prednostim nič izpadov / modro zelene uvedbe, podjetja ponavadi sledijo naslednjemu varnejšemu postopku za uvajanje svojih aplikacij:

  • pripraviti paket z novo različico aplikacije
  • zaustavi zagnano aplikacijo
  • zaženite skripte za selitev baze podatkov
  • namestite in zaženite novo različico aplikacije

V tem članku bomo podrobno opisali, kako lahko delate s svojo bazo podatkov in kodo, da izkoristite prednost uvajanja brez izpadov.

Težave z bazo podatkov

Če imate aplikacijo brez statusa, ki ne shranjuje nobenih podatkov v zbirko podatkov, lahko takoj zagotovite nič izpadov uvajanja. Na žalost mora večina programske opreme nekje shraniti podatke. Zato morate dvakrat premisliti, preden naredite kakršne koli spremembe v vezju. Preden se lotimo podrobnosti o tem, kako spremeniti shemo, tako da je možna uvedba brez izpadov, se najprej osredotočimo na shemo različic.

Shema različic

V tem članku bomo uporabili Flyway kot orodje za nadzor različic (pribl. Prevod: govorimo o selitvah baze podatkov). Seveda bomo napisali tudi aplikacijo Spring Boot, ki ima vgrajeno podporo za Flyway in bo izvedla migracijo sheme med nastavljanjem konteksta aplikacije. Ko uporabljate Flyway, lahko shranite selitvene skripte v mapo svojih projektov (privzeto v classpath:db/migration). Tukaj si lahko ogledate primer takih selitvenih datotek

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

V tem primeru vidimo 4 selitvene skripte, ki se bodo ob zagonu aplikacije, če niso bili izvedeni prej, izvajali drug za drugim. Poglejmo eno od datotek (V1__init.sql) kot primer.

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

Vse je popolnoma samoumevno: s SQL lahko določite, kako naj se spremeni vaša baza podatkov. Za več informacij o Spring Boot in Flyway si oglejte Pomladni zagonski dokumenti.

Z uporabo orodja za nadzor vira s programom Spring Boot dobite 2 veliki prednosti:

  • ločite spremembe baze podatkov od sprememb kode
  • Selitev baze podatkov poteka skupaj z uvedbo vaše aplikacije, tj. vaš postopek uvajanja je poenostavljen

Odpravljanje težav z bazo podatkov

V naslednjem delu članka se bomo osredotočili na dva pristopa k spremembam baze podatkov.

  • nezdružljivost za nazaj
  • združljivost za nazaj

Prvo bomo razumeli kot opozorilo, da brez predhodne priprave ne izvajajte uvajanja z ničelnim izpadom ... Drugi ponuja rešitev, kako lahko izvedete uvajanje brez izpadov in hkrati ohranite združljivost za nazaj.

Naš projekt, na katerem bomo delali, bo preprosta aplikacija Spring Boot Flyway, ki ima Person с first_name и last_name v bazi (pribl. prevod: Person je miza in first_name и last_name - to so polja v njem). Želimo preimenovati last_name в surname.

Predpostavke

Preden se lotimo podrobnosti, moramo narediti nekaj predpostavk o naših aplikacijah. Glavni rezultat, ki ga želimo doseči, bo dokaj preprost postopek.

Opomba. Poslovni PRO-NASVET. Poenostavitev postopkov vam lahko prihrani veliko denarja za podporo (več ljudi kot imate zaposlenih v vašem podjetju, več denarja lahko prihranite)!

Baze podatkov ni treba vrniti nazaj

To poenostavi postopek uvajanja (nekatere povrnitve baze podatkov so skoraj nemogoče, kot je povrnitev izbrisa). Raje vrnemo samo aplikacije. Na ta način, tudi če imate različne zbirke podatkov (na primer SQL in NoSQL), bo vaš cevovod za uvajanje videti enak.

Aplikacijo mora biti VEDNO mogoče vrniti za eno različico (ne več)

Povratek je treba izvesti le, kadar je to potrebno. Če je v trenutni različici napaka, ki je ni enostavno odpraviti, bi morali imeti možnost povrniti najnovejšo delujočo različico. Predvidevamo, da je ta zadnja delujoča različica prejšnja. Ohranjanje združljivosti kode in baze podatkov za več kot eno uvedbo bi bilo izjemno težko in drago.

Opomba. Za večjo berljivost bomo v tem članku spremenili glavno različico aplikacije.

1. korak: Začetno stanje

Različica aplikacije: 1.0.0
Različica DB: v1

Komentar

To bo začetno stanje aplikacije.

Spremembe baze podatkov

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

Spremembe kode

Aplikacija shranjuje podatke o osebah v 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
                + "]";
    }
}

Za nazaj nezdružljivo preimenovanje stolpcev

Oglejmo si primer, kako spremeniti ime stolpca:

Pozor. Naslednji primer bo namerno pokvaril stvari. To prikazujemo, da pokažemo težavo združljivosti baze podatkov.

Različica aplikacije: 2.0.0.BAD

Različica DB: v2bad

Komentar

Trenutne spremembe nam NE dovoljujejo izvajanja dveh primerkov (starega in novega) hkrati. Tako bo težko doseči uvedbo brez izpadov (če upoštevamo predpostavke, je to pravzaprav nemogoče).

A/B testiranje

Trenutno stanje je, da imamo različico aplikacije 1.0.0, razporejen v produkciji in bazi podatkov v1. Razmestiti moramo drugi primerek aplikacije, različico 2.0.0.BADin posodobi bazo podatkov na v2bad.

Koraki:

  1. nameščen je nov primerek aplikacije različice 2.0.0.BADki posodobi bazo podatkov na v2bad
  2. v zbirki podatkov v2bad stolpec last_name ne obstaja več - spremenjeno je bilo v surname
  3. Posodobitev baze podatkov in aplikacije je bila uspešna in nekateri primerki se izvajajo 1.0.0, drugi - v 2.0.0.BAD. Vse je povezano z bazo podatkov v2bad
  4. vse primerke različice 1.0.0 bodo začeli pošiljati napake, ker bodo poskušali vstaviti podatke v stolpec last_nameki ne obstaja več
  5. vse primerke različice 2.0.0.BAD bo delal brez težav

Kot lahko vidite, če naredimo nazaj nezdružljive spremembe baze podatkov in aplikacije, A/B testiranje ni mogoče.

Povrnitev aplikacije

Predpostavimo, da po poskusu uvedbe A/B (pribl. per.: verjetno je avtor tukaj mislil A/B testiranje) odločili smo se, da moramo aplikacijo povrniti na različico 1.0.0. Recimo, da ne želimo povrniti baze podatkov.

Koraki:

  1. ustavimo primerek aplikacije različice 2.0.0.BAD
  2. baza podatkov je še vedno v2bad
  3. od različice 1.0.0 ne razume, kaj je surname, bomo videli napake
  4. pekel se je začel, ne moremo več nazaj

Kot lahko vidite, če naredimo nazaj nezdružljive spremembe v zbirki podatkov in aplikaciji, se ne moremo vrniti na prejšnjo različico.

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

Spremembe baze podatkov

Skript za selitev, ki preimenuje last_name в surname

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

Skripta, ki preimenuje last_name.

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

Spremembe kode

Spremenili smo ime polja lastName o surname.

Preimenovanje stolpca na nazaj združljiv način

To je najpogostejša situacija, s katero se lahko srečamo. Narediti moramo nazaj nezdružljive spremembe. Dokazali smo že, da za uvajanje brez izpadov ne bi smeli preprosto uporabiti selitve baze podatkov brez dodatnih korakov. V tem razdelku članka bomo izvedli 3 uvedbe aplikacije skupaj s selitvami baze podatkov, da dosežemo želeni rezultat in hkrati ohranimo združljivost za nazaj.

Opomba. Spomnimo se, da imamo bazo podatkov o različicah v1. Vsebuje stolpce first_name и last_name. Spremeniti se moramo last_name o surname. Imamo tudi različico aplikacije 1.0.0, ki še ni v uporabi surname.

2. korak: Dodajte priimek

Različica aplikacije: 2.0.0
Različica DB: v2

Komentar

Z dodajanjem novega stolpca in kopiranjem njegove vsebine ustvarimo nazaj združljive spremembe baze podatkov. Hkrati pa, če vrnemo datoteko JAR nazaj v prejšnje stanje ali pustimo teči staro datoteko JAR, se ta med izvajanjem ne bo pokvarila.

Uvajamo novo različico

Koraki:

  1. izvedite selitev baze podatkov, da ustvarite nov stolpec surname. Zdaj vaša različica baze podatkov v2
  2. kopiraj podatke iz last_name в surname. Обратите вниманиеče imate veliko teh podatkov, razmislite o paketni selitvi!
  3. napišite kodo, kjer se uporabljajo OBOJE и NovIn stari stolpec. Zdaj vaša različica aplikacije 2.0.0
  4. preberite vrednost iz stolpca surname, če ni null, oziroma od last_nameče surname ni določeno. Lahko izbrišete getLastName() iz kode, saj bo izpisala null pri povrnitvi aplikacije iz 3.0.0 za 2.0.0.

Če uporabljate Spring Boot Flyway, bosta ta dva koraka izvedena med zagonom različice 2.0.0 aplikacije. Če ročno zaženete orodje za različice baze podatkov, boste morali za to narediti dve različni stvari (najprej ročno posodobite različico baze podatkov in nato uvedite novo aplikacijo).

Pomembno je. Ne pozabite, da je na novo ustvarjen stolpec NE BI SMEL biti NI NULL. Če naredite povrnitev, stara aplikacija ne pozna novega stolpca in ga med tem ne bo namestila Insert. Toda če dodate to omejitev in bo vaš db v2, bo to zahtevalo nastavitev vrednosti novega stolpca. Kar bo vodilo do kršitev omejitev.

Pomembno je. Metodo morate odstraniti getLastName(), saj v različici 3.0.0 V kodi ni koncepta stolpca last_name. To pomeni, da bo tam nastavljena ničelna vrednost. Metodo lahko zapustite in dodate preverjanja za null, vendar bi bila veliko boljša rešitev zagotoviti, da je v logiki getSurname() izbrali ste pravilno vrednost, ki ni nič.

A/B testiranje

Trenutno stanje je, da imamo različico aplikacije 1.0.0, razporejen v produkciji, baza podatkov pa v v1. Razmestiti moramo drugi primerek aplikacije različice 2.0.0ki bo posodobil bazo podatkov na v2.

Koraki:

  1. nameščen je nov primerek aplikacije različice 2.0.0ki posodobi bazo podatkov na v2
  2. medtem so nekatere zahteve obdelale instance različice 1.0.0
  3. posodobitev je bila uspešna in imate več delujočih primerkov aplikacije različice 1.0.0 in druge različice 2.0.0. Vsi komunicirajo z bazo podatkov v v2
  4. različica 1.0.0 v bazi podatkov ne uporablja stolpca priimkov, ampak različico 2.0.0 uporablja. Ne motijo ​​se drug drugega in ne bi smelo biti napak.
  5. različica 2.0.0 shranjuje podatke v starem in novem stolpcu, kar zagotavlja združljivost za nazaj

Pomembno je. Če imate kakršne koli poizvedbe, ki štejejo elemente na podlagi vrednosti iz starega/novega stolpca, ne pozabite, da imate zdaj podvojene vrednosti (najverjetneje se še selijo). Na primer, če želite prešteti število uporabnikov, katerih priimek (ne glede na ime stolpca) se začne s črko A, nato dokler selitev podatkov ni končana (oldnew stolpec) boste morda imeli nedosledne podatke, če poizvedujete po novem stolpcu.

Povrnitev aplikacije

Zdaj imamo različico aplikacije 2.0.0 in bazo podatkov v v2.

Koraki:

  1. povrnite aplikacijo na različico 1.0.0.
  2. različica 1.0.0 ne uporablja stolpca v bazi podatkov surname, zato mora biti povrnitev uspešna

spremembe DB

Baza podatkov vsebuje stolpec z imenom last_name.

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

Dodaj skript surname.

Pozor. Ne pozabite, da stolpcu, ki ga dodajate, NE MORETE DODATI nobenih omejitev NOT NULL. Če JAR vrnete nazaj, stara različica ne bo imela pojma o dodanem stolpcu in ga bo samodejno nastavila na NULL. Če obstaja takšna omejitev, se bo stara aplikacija preprosto zlomila.

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

Spremembe kode

Podatke hranimo kot last_name, in v surname. Hkrati beremo iz last_name, saj je ta stolpec najpomembnejši. Med postopkom uvajanja je nekatere zahteve morda obdelal primerek aplikacije, ki še ni bil posodobljen.

/*
 * 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. korak: odstranitev priimka iz kode

Različica aplikacije: 3.0.0

Različica DB:v3

Komentar

Opomba per.: Očitno je avtor v izvirnem članku pomotoma kopiral besedilo tega bloka iz 2. koraka. V tem koraku je treba spremeniti kodo aplikacije, da bi odstranili funkcionalnost, ki uporablja stolpec last_name.

Z dodajanjem novega stolpca in kopiranjem njegove vsebine smo ustvarili nazaj združljive spremembe baze podatkov. Poleg tega, če vrnemo datoteko JAR nazaj v prejšnje stanje ali izvajamo staro datoteko JAR, se ta med izvajanjem ne bo pokvarila.

Povrnitev aplikacije

Trenutno imamo različico aplikacije 3.0.0 in bazo podatkov v3. Različica 3.0.0 ne shranjuje podatkov v last_name. To pomeni, da v surname shranjene so najsodobnejše informacije.

Koraki:

  1. povrnite aplikacijo na različico 2.0.0.
  2. različica 2.0.0 uporablja in last_name и surname.
  3. različica 2.0.0 bo surname, če ni nič, sicer -last_name

Spremembe baze podatkov

V bazi podatkov ni strukturnih sprememb. Za izvedbo končne selitve starih podatkov se izvede naslednji 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;

Spremembe kode

Opomba per.: Avtor je pomotoma kopiral tudi opis tega bloka iz 2. koraka. V skladu z logiko članka bi morale biti spremembe v kodi v tem koraku namenjene odstranitvi elementov, ki delujejo s stolpcem last_name.

Podatke hranimo kot last_name, in v surname. Dodatno beremo iz stolpca last_name, saj je najbolj relevanten. Med postopkom uvajanja lahko nekatere zahteve obdela instanca, ki še ni bila nadgrajena.

/*
 * 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. korak: Odstranjevanje last_name iz baze podatkov

Različica aplikacije: 4.0.0

Različica DB: v4

Komentar

Zaradi dejstva, da koda različice 3.0.0 ni uporabil stolpca last_name, se med izvajanjem ne bo zgodilo nič slabega, če se vrnemo na 3.0.0 po odstranitvi stolpca iz baze podatkov.

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

spremembe DB

Relativno v3 samo odstranimo stolpec last_name in dodajte manjkajoče omejitve.

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

Spremembe kode

Koda ni sprememb.

Izhod

Uspešno smo uporabili nazaj nezdružljivo spremembo imena stolpca z izvedbo več nazaj združljivih uvedb. Spodaj je povzetek izvedenih dejanj:

  1. uvedba različice aplikacije 1.0.0 с v1 shema baze podatkov (ime stolpca = last_name)
  2. uvedba različice aplikacije 2.0.0, ki shranjuje podatke v last_name и surname. Aplikacija se bere iz last_name. Baza podatkov je v različici v2ki vsebuje stolpce, kot je last_nameIn surname. surname je kopija last_name. (OPOMBA: Ta stolpec ne sme imeti omejitve, da ni nič)
  3. uvedba različice aplikacije 3.0.0, ki shranjuje samo podatke v surname in se bere iz priimka. Kar zadeva bazo podatkov, poteka zadnja migracija last_name в surname. Tudi omejitev NI NULL odstranjen iz last_name. Baza podatkov je zdaj v različici v3
  4. uvedba različice aplikacije 4.0.0 - koda se ne spreminja. Razmestitev baze podatkov v4, ki odstrani last_name. Tukaj lahko v bazo podatkov dodate vse manjkajoče omejitve.

Če sledite temu pristopu, lahko vedno vrnete eno različico nazaj, ne da bi prekinili združljivost baze podatkov/aplikacije.

Koda:

Vsa koda, uporabljena v tem članku, je na voljo na GitHub. Spodaj je dodaten opis.

Projekti

Po kloniranju repozitorija boste videli naslednjo strukturo map.

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

Skripte

Zaženete lahko skripte, opisane v spodnjih skriptih, ki bodo prikazale nazaj združljive in nezdružljive spremembe baze podatkov.

Če si želite ogledati primeru z nazaj združljivimi spremembami, teči:

./scripts/scenario_backward_compatible.sh

In videti primeru z nazaj nezdružljivimi spremembami, teči:

./scripts/scenario_backward_incompatible.sh

Vzorec vzmetnega škornja Flyway

Vsi primeri so vzeti iz Spring Boot Sample Flyway.

Lahko si ogledate http://localhost:8080/flyway, obstaja seznam skriptov.

Ta primer vključuje tudi konzolo H2 (pri http://localhost:8080/h2-console), tako da si lahko ogledate stanje baze podatkov (privzeti URL jdbc je jdbc:h2:mem:testdb).

dodatno

Preberite tudi druge članke na našem blogu:

Vir: www.habr.com

Dodaj komentar