Š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į
Š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:
diegiamas naujas versijos programos egzempliorius 2.0.0.BADkuri atnaujina duomenų bazę į v2bad
duomenų bazėje v2bad stulpelį last_name nebėra – buvo pakeista į surname
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
visi versijos atvejai 1.0.0 pradės mesti klaidas, nes bandys įterpti duomenis į stulpelį last_namekurio jau nebėra
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:
sustabdome versijos programos egzempliorių 2.0.0.BAD
duomenų bazė vis dar yra v2bad
nuo versijos 1.0.0 nesupranta kas tai yra surname, pamatysime klaidas
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:
atlikite duomenų bazės perkėlimą, kad sukurtumėte naują stulpelį surname. Dabar jūsų DB versija v2
kopijuoti duomenis iš last_name в surname. Обратите вниманиеkad jei turite daug šių duomenų, turėtumėte apsvarstyti paketinį perkėlimą!
parašykite kodą, kur jie naudojami ABU и naujasIr старый stulpelyje. Dabar jūsų programos versija 2.0.0
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:
diegiamas naujas versijos programos egzempliorius 2.0.0kuri atnaujina duomenų bazę į v2
tuo tarpu kai kurios užklausos buvo apdorojamos versijų egzemplioriais 1.0.0
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
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ų.
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 (old → new 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:
grąžinkite programą į versiją 1.0.0.
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:
grąžinkite programą į versiją 2.0.0.
versija 2.0.0 naudoja ir last_name и surname.
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:
programos versijos diegimas 1.0.0 с v1 duomenų bazės schema (stulpelio pavadinimas = last_name)
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)
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
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).