Nulinis prastovų diegimas ir duomenų bazės

Nulinis prastovų diegimas ir duomenų bazės

Šiame straipsnyje išsamiai paaiškinama, kaip išspręsti duomenų bazės suderinamumo problemas diegiant. Mes jums pasakysime, kas gali nutikti jūsų gamybos programoms, jei bandysite įdiegti be išankstinio pasiruošimo. Tada pereisime per programos gyvavimo ciklo etapus, kurių reikia, kad prastovos būtų nulinės (apytiksliai juosta: toliau - nulis prastovų). Mūsų operacijų rezultatas bus atgalinio nesuderinamo duomenų bazės pakeitimo pritaikymas atgaline tvarka suderinamu būdu.

Jei norite suprasti kodo pavyzdžius iš straipsnio, galite juos rasti adresu GitHub.

įvedimas

Nulinis prastovų diegimas

Kokia mistika nulinis prastovų diegimas? Galima sakyti, kad tai yra tada, kai jūsų programa yra įdiegta taip, kad galėtumėte sėkmingai pristatyti naują programos versiją gamybinėje versijoje, o vartotojas nepastebi jos nepasiekiamumo. Žvelgiant iš vartotojo ir įmonės perspektyvos, tai yra geriausias įmanomas diegimo scenarijus, nes jis leidžia be trikdžių įdiegti naujas funkcijas ir ištaisyti klaidas.

Kaip tai pasiekti? Yra keletas būdų, čia yra vienas iš jų:

  • įdiegti savo paslaugos versiją Nr. 1
  • atlikti duomenų bazės perkėlimą
  • Įdiekite savo paslaugos 2 versiją lygiagrečiai su 1 versija
  • Kai tik pamatysite, kad 2 versija veikia taip, kaip turėtų, pašalinkite 1 versiją
  • pasiruošęs!

Lengva, ar ne? Deja, tai nėra taip paprasta, ir mes į tai išsamiai pažvelgsime vėliau. Dabar patikrinkime kitą gana įprastą diegimo procesą – mėlynai žalią diegimą.

Ar kada nors girdėjote mėlyna žalia dislokacija? Cloud Foundry tai labai palengvina. Tik pažiūrėk Šis straipsnis, kur tai aprašome išsamiau. Norėdami trumpai apibendrinti, priminsime, kaip atlikti mėlynai žalią diegimą:

  • įsitikinkite, kad veikia dvi jūsų gamybos kodo kopijos („mėlyna“ ir „žalia“);
  • visą srautą nukreipti į mėlynąją aplinką, t.y. kad gamybos URL nukreiptų ten;
  • įdiegti ir išbandyti visus programos pakeitimus žalioje aplinkoje;
  • perjungti URL iš mėlynos į žalią aplinką

Mėlynai žalias diegimas yra metodas, leidžiantis lengvai įdiegti naujas funkcijas, nesijaudinant, kad gamyba nutrūks. Taip yra dėl to, kad net jei kas nors atsitiks, galite lengvai grįžti į ankstesnę aplinką tiesiog „paspaudę jungiklį“.

Perskaitę visa tai, kas išdėstyta aukščiau, galite užduoti klausimą: ką bendro turi nulinės prastovos su Blue Green diegimu?

Na, jie turi gana daug bendro, nes norint išlaikyti dvi tos pačios aplinkos kopijas, jas išlaikyti reikia dvigubai pastangų. Štai kodėl kai kurios komandos teigia Martinas Fowleris, vadovaukitės šio metodo variantu:

Kita galimybė yra naudoti tą pačią duomenų bazę, kuriant mėlynai žalius jungiklius žiniatinklio ir domeno sluoksniams. Taikant šį metodą, duomenų bazė dažnai gali būti problema, ypač kai reikia pakeisti jos schemą, kad būtų palaikoma nauja programinės įrangos versija.

Ir čia mes prieiname prie pagrindinės šio straipsnio problemos. Duomenų bazė. Dar kartą pažvelkime į šią frazę.

atlikti duomenų bazės perkėlimą.

Dabar jūs turite užduoti sau klausimą – ką daryti, jei duomenų bazės pakeitimas nėra suderinamas atgal? Ar nesuges mano pirmoji programos versija? Tiesą sakant, būtent taip ir nutiks...

Taigi, net nepaisant didžiulių nulinės prastovos / mėlynai žalios spalvos diegimo pranašumų, įmonės yra linkusios laikytis toliau nurodyto saugesnio savo programų diegimo proceso:

  • paruošti paketą su nauja programos versija
  • išjunkite veikiančią programą
  • paleiskite scenarijus, kad perkeltumėte duomenų bazę
  • įdiegti ir paleisti naują programos versiją

Šiame straipsnyje išsamiai paaiškinsime, kaip galite dirbti su savo duomenų baze ir kodu, kad galėtumėte pasinaudoti nulinės prastovos diegimo pranašumais.

Duomenų bazės problemos

Jei turite programą be būsenos, kuri nesaugo jokių duomenų duomenų bazėje, galite iš karto gauti nulinės prastovos diegimą. Deja, dauguma programinės įrangos turi kažkur saugoti duomenis. Štai kodėl prieš atlikdami bet kokius grandinės pakeitimus turėtumėte gerai pagalvoti. Prieš pradėdami išsamią informaciją apie tai, kaip pakeisti schemą, kad būtų galima įdiegti be prastovų, pirmiausia sutelkime dėmesį į versijų kūrimo schemą.

Versijų kūrimo schema

Šiame straipsnyje mes naudosime Flyway kaip versijos valdymo įrankis (apytiksliai Vertimas: mes kalbame apie duomenų bazių perkėlimą). Natūralu, kad taip pat parašysime „Spring Boot“ programą, kuri turi integruotą „Flyway“ palaikymą ir atliks schemos perkėlimą nustatydami programos kontekstą. Naudodami „Flyway“, galite saugoti perkėlimo scenarijus savo projektų aplanke (pagal numatytuosius nustatymus classpath:db/migration). Čia galite pamatyti tokių perkėlimo failų pavyzdį

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

Šiame pavyzdyje matome 4 perkėlimo scenarijus, kurie, jei anksčiau nebuvo vykdomi, bus vykdomi vienas po kito, kai programa paleidžiama. Pažiūrėkime į vieną iš failų (V1__init.sql) pavyzdžiui.

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

Viskas yra visiškai savaime aišku: galite naudoti SQL, kad apibrėžtumėte, kaip turėtų būti modifikuota jūsų duomenų bazė. Norėdami gauti daugiau informacijos apie Spring Boot ir Flyway, žr Spring Boot Docs.

Naudodami šaltinio valdymo įrankį su Spring Boot gausite 2 didelius privalumus:

  • atskiriate duomenų bazės pakeitimus nuo kodo pakeitimų
  • Duomenų bazės perkėlimas vyksta kartu su jūsų programos išleidimu, t.y. jūsų diegimo procesas yra supaprastintas

Duomenų bazės trikčių šalinimas

Kitoje straipsnio dalyje mes sutelksime dėmesį į du duomenų bazės pakeitimų metodus.

  • atgalinis nesuderinamumas
  • atgalinis suderinamumas

Pirmasis bus laikomas įspėjimu, kad neturėtumėte atlikti nulinės prastovos diegimo be išankstinio pasiruošimo... Antrasis siūlo sprendimą, kaip galite atlikti diegimą be prastovų ir tuo pačiu išlaikyti atgalinį suderinamumą.

Mūsų projektas, su kuriuo dirbsime, bus paprasta „Spring Boot Flyway“ programa, turinti Person с first_name и last_name duomenų bazėje (apytiksliai vertimas: Person yra lentelė ir first_name и last_name - tai laukai jame). Norime pervadinti last_name в surname.

Prielaidos

Prieš įsigilindami į detales, turime padaryti keletą prielaidų apie mūsų programas. Pagrindinis rezultatas, kurį norime pasiekti, bus gana paprastas procesas.

Pastaba. Verslo PRO-TIP. Supaprastinus procesus galite sutaupyti daug pinigų iš paramos (kuo daugiau žmonių dirba jūsų įmonėje, tuo daugiau pinigų galite sutaupyti)!

Nereikia grąžinti duomenų bazės

Tai supaprastina diegimo procesą (kai kurių duomenų bazių grąžinimas beveik neįmanomas, pvz., panaikinimo atšaukimas). Norime grąžinti tik programas. Tokiu būdu, net jei turite skirtingas duomenų bazes (pavyzdžiui, SQL ir NoSQL), jūsų diegimo dujotiekis atrodys taip pat.

VISADA turi būti įmanoma grąžinti programą viena versija atgal (ne daugiau)

Atšaukimas turėtų būti atliekamas tik tada, kai reikia. Jei esamoje versijoje yra klaida, kuri nėra lengvai ištaisoma, turėtume turėti galimybę grįžti į naujausią veikiančią versiją. Manome, kad ši naujausia darbinė versija yra ankstesnė. Išlaikyti kodo ir duomenų bazės suderinamumą daugiau nei vieną kartą būtų labai sunku ir brangu.

Pastaba. Kad būtų lengviau skaityti, šiame straipsnyje pakeisime pagrindinę programos versiją.

1 veiksmas: pradinė būsena

Programos versija: 1.0.0
DB versija: v1

Komentuoti

Tai bus pradinė programos būsena.

Duomenų bazės pakeitimai

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

Kodo pakeitimai

Programa išsaugo asmens duomenis 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
                + "]";
    }
}

Atgalinis nesuderinamas stulpelių pervardijimas

Pažvelkime į pavyzdį, kaip pakeisti stulpelio pavadinimą:

Dėmesio. Šis pavyzdys tyčia sugadins dalykus. Tai parodome norėdami parodyti duomenų bazės suderinamumo problemą.

Programos versija: 2.0.0.BAD

DB versija: v2bad

Komentuoti

Dabartiniai pakeitimai NEGALIMA paleisti dviejų egzempliorių (senų ir naujų) vienu metu. Taigi, nulinį prastovų diegimą bus sunku pasiekti (jei bus atsižvelgta į prielaidas, tai iš tikrųjų neįmanoma).

A/B testavimas

Dabartinė situacija yra tokia, kad turime programos versiją 1.0.0, įdiegta gamyboje ir duomenų bazėje v1. Turime įdiegti antrą programos egzempliorių, versiją 2.0.0.BADir atnaujinkite duomenų bazę į v2bad.

Veiksmai:

  1. diegiamas naujas versijos programos egzempliorius 2.0.0.BADkuri atnaujina duomenų bazę į v2bad
  2. duomenų bazėje v2bad stulpelį last_name nebėra – buvo pakeista į surname
  3. Duomenų bazės ir programos atnaujinimas buvo sėkmingas, o kai kurie egzemplioriai veikia 1.0.0, kiti – į 2.0.0.BAD. Viskas prijungta prie duomenų bazės v2bad
  4. visi versijos atvejai 1.0.0 pradės mesti klaidas, nes bandys įterpti duomenis į stulpelį last_namekurio jau nebėra
  5. visi versijos atvejai 2.0.0.BAD veiks be problemų

Kaip matote, jei duomenų bazėje ir programoje atliekame atgal nesuderinamus pakeitimus, A/B testavimas yra neįmanomas.

Programos grąžinimas

Tarkime, kad pabandžius atlikti A/B diegimą (apytiksliai per.: autorius čia tikriausiai turėjo omenyje A/B testavimą) nusprendėme, kad turime grąžinti programos versiją 1.0.0. Tarkime, kad nenorime grąžinti duomenų bazės.

Veiksmai:

  1. sustabdome versijos programos egzempliorių 2.0.0.BAD
  2. duomenų bazė vis dar yra v2bad
  3. nuo versijos 1.0.0 nesupranta kas tai yra surname, pamatysime klaidas
  4. pragaras atsilaisvino, mes nebegalime grįžti

Kaip matote, jei duomenų bazėje ir programoje atliekame atgal nesuderinamus pakeitimus, negalime grįžti prie ankstesnės versijos.

Scenarijaus vykdymo žurnalai

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

Duomenų bazės pakeitimai

Migracijos scenarijus, kuris pervardija last_name в surname

Šaltinis Flyway scenarijus:

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

Pervardijantis scenarijus last_name.

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

Kodo pakeitimai

Mes pakeitėme lauko pavadinimą lastName apie surname.

Stulpelio pervadinimas atgaline tvarka suderinamu būdu

Tai yra dažniausia situacija, su kuria galime susidurti. Turime atlikti atgal nesuderinamus pakeitimus. Jau įrodėme, kad diegiant be prastovos neturėtume tiesiog taikyti duomenų bazės perkėlimo be papildomų veiksmų. Šioje straipsnio dalyje mes atliksime 3 programos diegimus kartu su duomenų bazės perkėlimu, kad pasiektume pageidaujamą rezultatą, išlaikant atgalinį suderinamumą.

Pastaba. Prisiminkite, kad turime versijų duomenų bazę v1. Jame yra stulpelių first_name и last_name. Turime pasikeisti last_name apie surname. Taip pat turime programos versiją 1.0.0, kuris dar nenaudojamas surname.

2 veiksmas: pridėkite pavardę

Programos versija: 2.0.0
DB versija: v2

Komentuoti

Pridėdami naują stulpelį ir nukopijavę jo turinį, sukuriame atgal suderinamus duomenų bazės pakeitimus. Tuo pačiu metu, jei atšauksime JAR arba paleisime seną JAR, vykdymo metu jis nesuges.

Išleidžiame naują versiją

Veiksmai:

  1. atlikite duomenų bazės perkėlimą, kad sukurtumėte naują stulpelį surname. Dabar jūsų DB versija v2
  2. kopijuoti duomenis iš last_name в surname. Обратите вниманиеkad jei turite daug šių duomenų, turėtumėte apsvarstyti paketinį perkėlimą!
  3. parašykite kodą, kur jie naudojami ABU и naujasIr старый stulpelyje. Dabar jūsų programos versija 2.0.0
  4. perskaitykite reikšmę iš stulpelio surname, jei taip nėra null, arba nuo last_name, jeigu surname nenurodyta. Galite ištrinti getLastName() iš kodo, nes jis bus išvestas null atšaukdami paraišką iš 3.0.0 į 2.0.0.

Jei naudojate Spring Boot Flyway, šie du veiksmai bus atlikti paleidžiant versiją 2.0.0 programos. Jei duomenų bazės versijų kūrimo įrankį paleisite rankiniu būdu, turėsite atlikti du skirtingus veiksmus (pirmiausia rankiniu būdu atnaujinti db versiją ir tada įdiegti naują programą).

Ji yra labai svarbi. Atminkite, kad naujai sukurtas stulpelis NETURĖTŲ būti NE NULL. Jei atšauksite, senoji programa nežino apie naują stulpelį ir jo neįdiegs Insert. Bet jei pridėsite šį apribojimą ir jūsų db bus v2, tam reikės nustatyti naujo stulpelio reikšmę. Dėl to bus pažeisti apribojimai.

Ji yra labai svarbi. Turėtumėte pašalinti metodą getLastName(), nes versijoje 3.0.0 Kode nėra stulpelio sąvokos last_name. Tai reiškia, kad ten bus nustatytas nulis. Galite palikti metodą ir pridėti čekius null, bet daug geresnis sprendimas būtų tuo įsitikinti pagal logiką getSurname() pasirinkote teisingą nulinę reikšmę.

A/B testavimas

Dabartinė situacija yra tokia, kad turime programos versiją 1.0.0, įdiegta gamyboje ir duomenų bazėje v1. Turime įdiegti antrąjį versijos programos egzempliorių 2.0.0kuri atnaujins duomenų bazę į v2.

Veiksmai:

  1. diegiamas naujas versijos programos egzempliorius 2.0.0kuri atnaujina duomenų bazę į v2
  2. tuo tarpu kai kurios užklausos buvo apdorojamos versijų egzemplioriais 1.0.0
  3. naujinimas buvo sėkmingas ir turite kelis versijos programos egzempliorius 1.0.0 ir kitos versijos 2.0.0. Visi bendrauja su duomenų baze v2
  4. versija 1.0.0 duomenų bazėje naudoja ne pavardės stulpelį, o versiją 2.0.0 naudoja. Jie netrukdo vienas kitam ir neturėtų būti klaidų.
  5. versija 2.0.0 saugo duomenis tiek sename, tiek naujame stulpelyje, užtikrinant atgalinį suderinamumą

Ji yra labai svarbi. Jei turite užklausų, kurios skaičiuoja elementus pagal senojo / naujo stulpelio reikšmes, turėtumėte atsiminti, kad dabar turite pasikartojančias vertes (greičiausiai jos vis dar perkeliamos). Pavyzdžiui, jei norite suskaičiuoti vartotojų, kurių pavardė (kad ir kaip būtų vadinamas stulpelis) prasidėjo raide A, tada kol duomenų perkėlimas bus baigtas (oldnew stulpelyje), galite turėti nenuoseklių duomenų, jei pateikiate užklausą dėl naujo stulpelio.

Programos grąžinimas

Dabar turime programos versiją 2.0.0 ir duomenų bazėje v2.

Veiksmai:

  1. grąžinkite programą į versiją 1.0.0.
  2. versija 1.0.0 duomenų bazėje nenaudoja stulpelio surname, todėl atšaukimas turėtų būti sėkmingas

DB pakeitimai

Duomenų bazėje yra stulpelis pavadinimu last_name.

Flyway šaltinio scenarijus:

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

Pridėti scenarijų surname.

Dėmesio. Atminkite, kad prie pridedamo stulpelio NEGALIMA PRIDĖTI jokių NOT NULL apribojimų. Jei atšauksite JAR, senoji versija neturės supratimo apie pridėtą stulpelį ir automatiškai nustatys jį į NULL. Jei yra toks apribojimas, senoji programa tiesiog suges.

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

Kodo pakeitimai

Duomenis saugome kaip last_nameir in surname. Tuo pačiu metu skaitome iš last_name, nes šis stulpelis yra pats aktualiausias. Diegimo proceso metu kai kurias užklausas galėjo apdoroti programos egzempliorius, kuris dar nebuvo atnaujintas.

/*
 * 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 veiksmas: pašalinkite pavardę iš kodo

Programos versija: 3.0.0

DB versija:v3

Komentuoti

Pastaba per.: Matyt, pirminiame straipsnyje autorius per klaidą nukopijavo šio bloko tekstą iš 2 veiksmo. Šiame žingsnyje reikia atlikti programos kodo pakeitimus, kuriais siekiama pašalinti stulpelį naudojančią funkciją last_name.

Pridėję naują stulpelį ir nukopijavę jo turinį, sukūrėme atgal suderinamus duomenų bazės pakeitimus. Be to, jei atšauksime JAR arba turėsime seną JAR, vykdymo metu jis nesuges.

Programos grąžinimas

Šiuo metu turime programos versiją 3.0.0 ir duomenų bazę v3. Versija 3.0.0 neišsaugo duomenų last_name. Tai reiškia, kad į surname saugoma pati naujausia informacija.

Veiksmai:

  1. grąžinkite programą į versiją 2.0.0.
  2. versija 2.0.0 naudoja ir last_name и surname.
  3. versija 2.0.0 užtruks surname, jei jis nėra nulis, kitaip -last_name

Duomenų bazės pakeitimai

Struktūrinių pakeitimų duomenų bazėje nėra. Šis scenarijus vykdomas norint atlikti galutinį senų duomenų perkėlimą:

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

Kodo pakeitimai

Pastaba per.: Šio bloko aprašymą autorius taip pat per klaidą nukopijavo iš 2 veiksmo. Remiantis straipsnio logika, šiame žingsnyje kodo pakeitimais turėtų būti siekiama pašalinti iš jo elementus, kurie veikia su stulpeliu last_name.

Duomenis saugome kaip last_nameir in surname. Be to, skaitome iš stulpelio last_name, nes tai aktualiausia. Diegimo proceso metu kai kurias užklausas gali apdoroti egzempliorius, kuris dar nebuvo atnaujintas.

/*
 * 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 veiksmas: pašalinkite pavardę iš duomenų bazės

Programos versija: 4.0.0

DB versija: v4

Komentuoti

Dėl to, kad versijos kodas 3.0.0 nenaudojo stulpelio last_name, nieko blogo vykdant nenutiks, jei grįšime prie 3.0.0 pašalinus stulpelį iš duomenų bazės.

Scenarijaus vykdymo žurnalai

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 pakeitimai

Apie v3 mes tiesiog pašaliname stulpelį last_name ir pridėkite trūkstamus apribojimus.

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

Kodo pakeitimai

Kode pakeitimų nėra.

Produkcija

Sėkmingai pritaikėme atgal nesuderinamą stulpelio pavadinimo pakeitimą, atlikdami keletą atgalinio suderinamumo diegimų. Žemiau pateikiama atliktų veiksmų santrauka:

  1. programos versijos diegimas 1.0.0 с v1 duomenų bazės schema (stulpelio pavadinimas = last_name)
  2. programos versijos diegimas 2.0.0, kuriame saugomi duomenys last_name и surname. Paraiška skaitoma iš last_name. Duomenų bazės versija v2kuriuose yra tokių stulpelių kaip last_nameIr surname. surname yra l kopijaast_name. (PASTABA: šiame stulpelyje neturi būti apribojimo, kuris nėra nulis)
  3. programos versijos diegimas 3.0.0, kuriame saugomi tik duomenys surname ir skaito iš pavardės. Kalbant apie duomenų bazę, vyksta paskutinis perkėlimas last_name в surname. Taip pat apribojimas NE NULL pašalintas iš last_name. Dabar duomenų bazės versija v3
  4. programos versijos diegimas 4.0.0 - kodo pakeitimai nedaromi. Duomenų bazės diegimas v4, kuris pašalina last_name. Čia galite pridėti visus trūkstamus duomenų bazės apribojimus.

Laikydamiesi šio metodo, visada galite grąžinti vieną versiją nepažeisdami duomenų bazės / programos suderinamumo.

Kodas

Visas šiame straipsnyje naudojamas kodas yra pasiekiamas adresu GitHub. Žemiau yra papildomas aprašymas.

Projektai

Klonavę saugyklą, pamatysite tokią aplanko struktūrą.

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

Scenarijai

Galite paleisti toliau pateiktuose scenarijuose aprašytus scenarijus, kurie parodys atgalinius ir nesuderinamus duomenų bazės pakeitimus.

Matyti atvejis su atgal suderinamais pakeitimais, paleisti:

./scripts/scenario_backward_compatible.sh

Ir pamatyti atvejis su atgal nesuderinamais pakeitimais, paleisti:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Visi pavyzdžiai paimti iš Spring Boot Sample Flyway.

Galite pasižiūrėti http://localhost:8080/flyway, yra scenarijų sąrašas.

Šiame pavyzdyje taip pat yra H2 konsolė (at http://localhost:8080/h2-console), kad galėtumėte peržiūrėti duomenų bazės būseną (numatytasis jdbc URL yra jdbc:h2:mem:testdb).

Be

Taip pat skaitykite kitus mūsų tinklaraščio straipsnius:

Šaltinis: www.habr.com

Добавить комментарий