
V tem članku podrobno razlagamo, kako reševati težave, povezane s združljivostjo baz podatkov med izvajanjem prenosa. Povedali vam bomo, kaj se lahko zgodi z vašimi aplikacijami v produkciji, če poskusite izvesti prenos brez predhodne priprave. Nato bomo prešli skozi etape življenjskega cikla aplikacije, ki so potrebne za dosego ničelnega časa nedelovanja (op. prev.: nadalje — zero downtime). Rezultat naših operacij bo uporaba nazaj nezdružljive spremembe baze podatkov na način, ki je spet združljiv.
Če želite raziskati primere kode iz članka, jih najdete na .
Uvod
Zero downtime deployment
Kaj je ta mistični zero downtime deployment? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.
Kako to doseči? Obstaja več načinov, tukaj je eden izmed njih:
- izvedite različico №1 vaše storitve
- izvedite migracijo BD
- izvedite različico № 2 vaše storitve vzporedno z različico № 1
- ko boste videli, da različica № 2 deluje, odstranite različico № 1
- končano!
Enostavno, mar ne? Na žalost to ni tako preprosto, in temu se bomo kasneje podrobno posvetili. Zdaj pa preverimo še en precej razširjen proces prenosa — blue green deployment.
Ste že slišali za ? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на , kjer to podrobneje opisujemo. Na kratko povzemimo, kako izvesti blue green deployment:
- zagotovite delovanje dveh kopij vašega produkcijskega kode (“blue” in “green”);
- usmerite ves promet v blue okolje, torej naj URL-ji produkcije kažejo tja;
- izvaja in testira vse spremembe aplikacije v green okolju;
- preklopite URL-ji iz blue na green okolje
Blue green deployment je pristop, ki omogoča enostavno uvajanje novih funkcij, ne da bi skrbeli, da bo produkcija zlomljena. To je povezano s dejstvom, da se lahko tudi če pride do težav, preprosto vrnete v prejšnje okolje, tako da preklopite.
Ko ste prebrali vse zgoraj navedeno, se morda sprašujete: Kakšno zvezo ima zero downtime z Blue green prenosom?
No, imata precej skupnega, saj podpiranje dveh kopij istega okolja zahteva dvojne napore za njihovo vzdrževanje. Zato nekatere ekipe, kot trdi , sledijo različici tega pristopa:
Druga možnost je uporaba iste baze podatkov, pri čemer se ustvarjajo modro-zelene preklopnike za spletne in domenske plasti. Pri temu pristopu so baze podatkov pogosto lahko problem, zlasti ko morate spremeniti njeno shemo za podporo nove različice programske opreme.
In tukaj pridemo do glavne težave v tem članku. База данных. Ponovno se osredotočimo na to frazo.
izvedite migracijo baze podatkov.
Zdaj se morate vprašati — kaj pa, če je povratna sprememba baze podatkov nezdružljiva? Ali se ne bo prva različica aplikacije podrla? Dejansko se to sploh zgodi…
Tako, kljub ogromnim prednostim brezprekinitvenega delovanja / modro-zelene uvedbe, podjetja običajno sledijo naslednjemu bolj varnemu procesu uvedbe svojih aplikacij:
- pripravite paket z novo različico aplikacije
- izklopite zagnano aplikacijo
- zažene skripte za migracijo baze podatkov
- razporedite in zaženite novo različico aplikacije
V tem članku bomo podrobno opisali, kako lahko delate z bazo podatkov in kodo, da izkoristite prednosti brezprekinitvenega uvajanja.
Težave z bazo podatkov
Če imate aplikacijo brez stanja, ki ne shranjuje nobenih podatkov v bazo, lahko takoj dosežete brezprekinitveno uvedbo. Na žalost večina programske opreme mora nekje shraniti podatke. Zato morate dvakrat premisliti, preden naredite kakršne koli spremembe v shemi. Preden se poglobimo v podrobnosti, kako spremeniti shemo tako, da je uvedba brez prekinitve mogoča, se najprej osredotočimo na shemo upravljanja različic.
Shema upravljanja različic
V tem članku bomo uporabljali kot orodje za upravljanje različic (op. prev.: gre za migracije baze podatkov). Seveda bomo tudi napisali aplikacijo Spring Boot, ki ima vgrajeno podporo za Flyway in bo izvedla migracijo sheme med nastavitvijo konteksta aplikacije. Pri uporabi Flyway lahko shranite skripte migracije v mapo vaših projektov (privzeto v classpath:db/migration). Tukaj lahko vidite primer takšnih datotek migracije
└── db
└── migration
├── V1__init.sql
├── V2__Add_surname.sql
├── V3__Final_migration.sql
└── V4__Remove_lastname.sqlV tem primeru vidimo 4 scenarije migracije, ki, če še niso bili izvedeni, se bodo izvajali zaporedno ob zagonu aplikacije. Poglejmo enega od datotek (V1__init.sql) kot primer.
Ustvari TABELA OSEBA (
id BIGINT GENERIRANO PRIVZETO KOT IDENTITETA,
first_name varchar(255) ne more biti prazno,
last_name varchar(255) ne more biti prazno
);
vstavi v OSEBA (first_name, last_name) vrednosti ('Dave', 'Syer');Vse odlično govori samo zase: lahko uporabite SQL, da določite, kako naj bo vaša baza podatkov spremenjena. Za več informacij o Spring Boot in Flyway si oglejte .
Z uporabo orodja za upravljanje različic s Spring Boot pridobite 2 velike prednosti:
- ločite spremembe v bazi podatkov od sprememb kode
- migracija baze podatkov poteka skupaj z izdajo vaše aplikacije, tj. vaš postopek nameščanja je poenostavljen
Reševanje težav z bazo podatkov
V naslednjem delu članka se bomo osredotočili na preučitev dveh pristopov k spremembam v bazi podatkov.
- nazaj nezdružljivost
- nazaj združljivost
Prvi bo obravnavan kot opozorilo, da ne smete izvajati namestitev brez ustavitve brez predhodne priprave … Drugi ponuja rešitev, kako lahko izvajate namestitev brez zastojev in hkrati ohranjate nazaj združljivost.
Naš projekt, na katerem bomo delali, bo preprosta aplikacija Spring Boot Flyway, v kateri je Oseba z first_name in last_name v bazi podatkov (op. prev.: Oseba je tabela, in first_name in last_name je polje v njej). Želimo preimenovati last_name u priimek.
Predpostavke
Preden se poglobimo v podrobnosti, je treba opredeliti nekaj predpostavk o naših aplikacijah. Glavni rezultat, ki ga želimo doseči, bo precej preprost postopek.
Opomba. POSLOVNI PRO-VRSTNI NASVET. Poenostavljanje procesov vam lahko prihrani veliko denarja pri vzdrževanju (več ljudi kot dela v vaši podjetju, več denarja lahko prihranite)!
Ne treba je izvajati povratka baze podatkov
To poenostavi postopek namestitve (nekatere povratke baze podatkov so praktično nemogoče, na primer povratek brisanja). Raje zgolj povratimo aplikacije. Tako, tudi če imate različne baze podatkov (na primer SQL in NoSQL), bo vaš postopek nameščanja izgledal enako.
Vedno naj bo mogoče vrniti aplikacijo eno različico nazaj (ne več)
Rollback should only be performed when necessary. If there is a bug in the current version that is difficult to fix, we must be able to revert to the last working version. We assume that this last working version is the previous one. Supporting code and database compatibility for more than one rollout would be extremely challenging and costly.
Opomba. For improved readability, throughout this article we will change the major version of the application.
Step 1: Initial state
Application version: 1.0.0
Database version: v1
Komentar
This will be the initial state of the application.
Database changes
Database contains 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');Code changes
The application saves Person data in 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
+ "]";
}
}Backward incompatible column renaming
Let's look at an example of how to rename a column:
Attention. The following example will intentionally cause a break. We show this to demonstrate the database compatibility issue.
Application version: 2.0.0.BAD
Database version: v2bad
Komentar
The current changes do NOT allow us to run two instances (old and new) simultaneously. Thus, zero downtime deployment will be hard to achieve (given the assumptions, it is essentially impossible).
A/B testing
The current situation is that we have an application version 1.0.0, deployed in production, and the database v1. We need to deploy a second instance of the application, version 2.0.0.BAD, and update the database to v2bad.
Koraki:
- new instance of the application version
2.0.0.BAD, which updates the database tov2bad - v bazi podatkov
v2badcolumnlast_nameno longer exists — it has been changed topriimek - the database and application update was successful, and some instances are running in
1.0.0, others in2.0.0.BAD. All are connected to the databasev2bad - all instances of version
1.0.0will start throwing errors because they will try to insert data into the columnlast_name, which no longer exists - all instances of version
2.0.0.BADwill work fine
As you can see, if we make backward incompatible changes to the database and application, A/B testing is not possible.
Application rollback
Let's assume that after trying to perform an A/B deployment (note: the author probably meant A/B testing here) we decided that we need to roll back the application to version 1.0.0. Let's say we don't want to roll back the database.
Koraki:
- Ugasimo instancu aplikacije verzije
2.0.0.BAD - baza podataka je još uvijek
v2bad - budući da verzija
1.0.0ne razumije šta jepriimek, vidjet ćemo greške - pakao se oslobodio, više se ne možemo vratiti
Kao što vidite, ako napravimo unazadne nekompatibilne promjene u bazi podataka i aplikaciji, ne možemo se vratiti na prethodnu verziju.
Logovi izvršavanja skripte
Scenario unazadne nekompatibilnosti:
01) Pokrenuti 1.0.0
02) Čekati da se aplikacija (1.0.0) pokrene
03) Generisati osobu pozivom POST localhost:9991/person na verziji 1.0.0
04) Pokrenuti 2.0.0.BAD
05) Čekati da se aplikacija (2.0.0.BAD) pokrene
06) Generisati osobu pozivom POST localhost:9991/person na verziji 1.0.0 <-- ovo bi trebalo da ne uspe
07) Generisati osobu pozivom POST localhost:9992/person na verziji 2.0.0.BAD <-- ovo bi trebalo da uspe
Pokrećem aplikaciju u verziji 1.0.0
Generisanje osobe u verziji 1.0.0
Slanje posta na 127.0.0.1:9991/person. Ovo je odgovor:
{"firstName":"b73f639f-e176-4463-bf26-1135aace2f57","lastName":"b73f639f-e176-4463-bf26-1135aace2f57"}
Pokrećem aplikaciju u verziji 2.0.0.BAD
Generisanje osobe u verziji 1.0.0
Slanje posta na 127.0.0.1:9991/person. Ovo je odgovor:
curl: (22) Zatražena URL adresa je vratila grešku: 500 Internal Server Error
Generisanje osobe u verziji 2.0.0.BAD
Slanje posta na 127.0.0.1:9995/person. Ovo je odgovor:
{"firstName":"e156be2e-06b6-4730-9c43-6e14cfcda125","surname":"e156be2e-06b6-4730-9c43-6e14cfcda125"}Database changes
Skripta za migraciju koja preimenuje last_name u priimek
Izvorna Flyway skripta:
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 koja preimenuje last_name.
-- Ova promjena je unazad nekompatibilna - ne možete raditi A/B testiranje
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;Code changes
Promenili smo ime polja lastName na priimek.
Preimenovanje kolumne na unazad kompatibilan način
Ovo je najčešća situacija sa kojom se možemo suočiti. Moramo izvršiti unazadne nekompatibilne promjene. Već smo dokazali da za deploy bez zastoja ne smijemo samo primijeniti migraciju baze podataka bez dodatnih koraka. U ovom dijelu članka radićemo 3 deploymenta aplikacije zajedno s migracijama baze podataka kako bismo postigli željeni rezultat i pritom zadržali unazad kompatibilnost.
Opomba. Podsjetimo se da imamo bazu podataka verzije
v1. Ona sadrži kolumnefirst_nameinlast_name. Moramo promijenitilast_namenapriimek. Takođe imamo aplikaciju verzije1.0.0,koja još ne koristipriimek.
Korak 2: Dodavanje surname
Application version: 2.0.0
Database version: v2
Komentar
Dodavanjem nove kolumne i kopiranjem njenog sadržaja, stvaramo unazadne kompatibilne promjene baze podataka. U isto vrijeme, ako se vratimo na JAR ili imamo funkcionalni stari JAR, neće se slomiti tokom izvršavanja.
Izdavanje nove verzije
Koraki:
- izvršite migraciju baze podataka kako biste stvorili novu kolumnu
priimek. Sada vaša baza podataka verzijev2 - kopirajte podatke iz
last_nameupriimek. Upoštevajte,, ako imate mnogo tih podataka, trebate razmotriti mogućnost serijske migracije! - napisite kod gde se koriste OBE in nov, i stari stolpec. Zdaj je vaša aplikacija različice
2.0.0 - preberite vrednost iz stolpca
priimek, če ninull, ali iz last_name, čepriimekni določeno. Lahko odstranitegetLastName()iz kode, saj bo izdajalnullpri vračanju vaše aplikacije3.0.0do2.0.0.
Če uporabljate Spring Boot Flyway, bosta ti dve koraki izvedeni ob zagonu različice 2.0.0 aplikacije. Če orodje za upravljanje različic baze podatkov zaženete ročno, boste morali za to opraviti dve različni dejanje (najprej ročno posodobite različico db, nato pa razporedite novo aplikacijo).
Važno. Zapomnite si, da novo ustvarjen stolpec NE SME biti NOT NULL. Če izvedete vračanje, stara aplikacija ne ve za nov stolpec in ga ne bo nastavila med
Vstavi.Ampak, če dodate to omejitev in vaša baza podatkovv2, bo to zahtevalo nastavitev vrednosti novega stolpca. To bo pripeljalo do kršitev omejitev.Važno. Priporočljivo je, da odstranite metodo
getLastName(), ker v različici3.0.0koda ne vsebuje pojma stolpcalast_name. To pomeni, da bodo postavljene null. Lahko pustite metodo in dodate preverjanja nanull, vendar bo veliko boljša rešitev zagotoviti, da ste v logikigetSurname()izbrali pravo nenull vrednost.
A/B testing
The current situation is that we have an application version 1.0.0, razporejeno v produkciji, in baza podatkov v v1. Moramo razporediti drugo instanco aplikacije različice 2.0.0, ki bo posodobila bazo podatkov do v2.
Koraki:
- new instance of the application version
2.0.0, which updates the database tov2 - medtem so nekatere poizvedbe obdelovali primerki različice
1.0.0 - posodobitev je potekala uspešno in imate več delujočih primerkov aplikacije različice
1.0.0in ostalih različic2.0.0.Vsi komunicirajo z bazo podatkov vv2 - različica
1.0.0ne uporablja v bazi podatkov stolpca surname, medtem ko različica2.0.0uporablja. Ne ovirajo se, in napak ne bi smelo biti. - različica
2.0.0hrani podatke tako v starem kot v novem stolpcu, kar zagotavlja združljivost nazaj
Važno. Če imate kakršne koli poizvedbe, ki štejejo elemente na podlagi vrednosti iz starega / novega stolpca, se morate spomniti, da zdaj imate podvajanje vrednosti (verjetno se še vedno migrirajo). Na primer, če želite prešteti število uporabnikov, katerih priimek (karkoli že je ime stolpca) se začne z črko
A, potem do zaključka migracije podatkov (old→novostolpec) imate lahko nekonsistentne podatke, če izvedete poizvedbo na novem stolpcu.
Application rollback
Zdaj imamo aplikacijo različice 2.0.0 in bazo podatkov v v2.
Koraki:
- vračite svojo aplikacijo na različico
1.0.0. - različica
1.0.0ne uporablja v bazi podatkov stolpcapriimek, zato je mora biti povrat uspešen
Spremembe DB
DB 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');Skript za dodajanje priimek.
Attention. Zapomnite si, da NI DOVOLJENO dodajati kakršne koli omejitve NOT NULL v dodani stolpec. Če boste vrnili JAR, stara različica ne bo imela pojma o dodanem stolpcu in ga bo samodejno nastavila na NULL. V primeru, da obstaja taka omejitev, bo staro aplikacijo preprosto zlomilo.
-- OPOMBA: Ta stolpec ne more imeti omejitve NOT NULL, ker, če boste vrnili, stara različica ne bo vedela za ta stolpec
-- in ga bo vedno nastavila na NULL
ALTER TABLE PERSON ADD surname varchar(255);
-- DOMNEVAMO, DA GRE ZA HITRO MIGRACIJO - V NASPROTJU S TEM BI MORALI MIGRIRATI V SERIJAH
UPDATE PERSON SET PERSON.surname = PERSON.last_nameCode changes
Shranjujemo podatke kot v last_name, kot tudi v priimek. Pri tem beremo iz last_name, saj je ta stolpec najaktualnejši. Med procesom nameščanja so lahko nekateri zahtevki obdelani s primerkom 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
+ "]";
}
}Korak 3: Odstranitev last_name iz kode
Application version: 3.0.0
Database version:v3
Komentar
Op. prev.: Po vsem sodeč je avtor v izvorni članku napačno skopiral besedilo tega bloka iz koraka 2. V tem koraku bi morala biti sprememba v kodi aplikacije, katere namen je odstranitev funkcionalnosti, ki uporablja stolpec last_name.
Z dodajanjem novega stolpca in kopiranjem njegove vsebine smo ustvarili nazaj združljive spremembe DB. Tudi, če bomo vrnili JAR ali imamo delujoči stari JAR, se med izvajanjem ne bo zlomil.
Application rollback
Trenutno imamo aplikacijo različice 3.0.0 in bazo podatkov v3. Različica 3.0.0 ne shranjuje podatkov v last_name. To pomeni, da v priimek je shranjena najaktualnejša informacija.
Koraki:
- vračite svojo aplikacijo na različico
2.0.0. - različica
2.0.0uporablja inlast_nameinpriimek. - različica
2.0.0bo vzelpriimek, če ni ničelno, drugače pa —last_name
Database changes
V DB ni strukturnih sprememb. Izvaja se naslednji skript, ki dokončuje končno migracijo starih podatkov:
-- DOMNEVAMO, DA GRE ZA HITRO MIGRACIJO - V NASPROTJU S TEM BI MORALI MIGRIRATI V SERIJAH
-- TUDI NE PREVERJAMO, ALI NE PREPIŠEMO OBSTOJEČIH VNOSOV. MORALI BI OPRAVITI
-- KOMPARED OPRAVITI VERSIJE VNOSOV, DA POSKRBIMO, DA, ČE OBSTAJA ŽE VNOS Z VIŠJO ŠTEVILKO VERZIJE
-- NE BODO PREKLICALI.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;
-- ODSTRANITE OMEJITEV NOT NULL; DRUGAČE BOMETA POSKUŠALI VSTAVITI NULL VREDNOST LAST_NAME
-- Z OMEJITVIJO NOT NULL.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;Code changes
Op. prev.: Opis tega bloka je bil tudi napačno skopiran avtorja iz koraka 2. V skladu z logiko pripovedi članka bi morale biti spremembe v kodi v tem koraku namenjene odstranitvi elementov, ki delujejo ze stolpcem last_name.
Shranjujemo podatke kot v last_name, kot tudi v surname. Poleg tega beremo iz stolpca last_name, ker je najbolj relevanten. Med uvedbo lahko nekateri poizvedbe obdeluje instanca, ki še ni bila posodobljena.
/*
* 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
+ "]";
}
}Korak 4: Odstranitev last_name iz Baze Podatkov
Application version: 4.0.0
Database version: v4
Komentar
Zaradi dejstva, da koda različice 3.0.0 ni uporabila stolpca last_name, med izvajanjem se ne bo zgodilo nič slabega, če se vrnemo k 3.0.0 po odstranitvi stolpca iz baze podatkov.
Logovi izvršavanja skripte
To bomo izvedli na naslednji način:
01) Zaženi 1.0.0
02) Počakaj, da se aplikacija (1.0.0) naloži
03) Ustvari osebo z klicem POST localhost:9991/person na različico 1.0.0
04) Zaženi 2.0.0
05) Počakaj, da se aplikacija (2.0.0) naloži
06) Ustvari osebo z klicem POST localhost:9991/person na različico 1.0.0
07) Ustvari osebo z klicem POST localhost:9992/person na različico 2.0.0
08) Ubij aplikacijo (1.0.0)
09) Zaženi 3.0.0
10) Počakaj, da se aplikacija (3.0.0) naloži
11) Ustvari osebo z klicem POST localhost:9992/person na različico 2.0.0
12) Ustvari osebo z klicem POST localhost:9993/person na različico 3.0.0
13) Ubiti aplikacijo (3.0.0)
14) Zaženi 4.0.0
15) Počakaj, da se aplikacija (4.0.0) naloži
16) Ustvari osebo z klicem POST localhost:9993/person na različico 3.0.0
17) Ustvari osebo z klicem POST localhost:9994/person na različico 4.0.0
Zagon aplikacije v različici 1.0.0
Ustvarjanje osebe v različici 1.0.0
Pošiljanje posta na 127.0.0.1:9991/person. To je odziv:
{"firstName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2","lastName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2"}
Zagon aplikacije v različici 2.0.0
Ustvarjanje osebe v različici 1.0.0
Pošiljanje posta na 127.0.0.1:9991/person. To je odziv:
{"firstName":"e41ee756-4fa7-4737-b832-e28827a00deb","lastName":"e41ee756-4fa7-4737-b832-e28827a00deb"}
Ustvarjanje osebe v različici 2.0.0
Pošiljanje posta na 127.0.0.1:9992/person. To je odziv:
{"firstName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","lastName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","surname":"0c1240f5-649a-4bc5-8aa9-cff855f3927f"}
Ubij aplikacijo 1.0.0
Zagon aplikacije v različici 3.0.0
Ustvarjanje osebe v različici 2.0.0
Pošiljanje posta na 127.0.0.1:9992/person. To je odziv:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}
Ustvarjanje osebe v različici 3.0.0
Pošiljanje posta na 127.0.0.1:9993/person. To je odziv:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}
Ubij aplikacijo 2.0.0
Zagon aplikacije v različici 4.0.0
Ustvarjanje osebe v različici 3.0.0
Pošiljanje posta na 127.0.0.1:9993/person. To je odziv:
{"firstName":"cbe942fc-832e-45e9-a838-0fae25c10a51","surname":"cbe942fc-832e-45e9-a838-0fae25c10a51"}
Ustvarjanje osebe v različici 4.0.0
Pošiljanje posta na 127.0.0.1:9994/person. To je odziv:
{"firstName":"ff6857ce-9c41-413a-863e-358e2719bf88","surname":"ff6857ce-9c41-413a-863e-358e2719bf88"}Spremembe Baze Podatkov
Glede na v3 preprosto odstranimo stolpec last_name in dodamo manjkajoče omejitve.
-- ODSTRANI STOLPEC
ALTER TABLE PERSON DROP last_name;
-- DODAJ OMEJITVE
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;Code changes
Spremembe v kodi niso prisotne.
Izlaz
Uspešno smo uporabili povratno nezdružljivo spremembo imena stolpca z izvedbo več povratno združljivih uvedb. Tukaj je povzetek izvedenih dejanj:
- uvoz aplikacije različice
1.0.0zv1shema Baze Podatkov (ime stolpca =last_name) - uvoz aplikacije različice
2.0.0,ki shranjuje podatke vlast_nameinpriimek. Aplikacija čita izlast_name. Baza podataka je u verzijiv2, koja sadrži kolone kao što sulast_name, kot tudisurname. prezimeje kopija last_name. (NAPOMENA: ova kolona ne sme imati ograničenje not null) - uvoz aplikacije različice
3.0.0, koja čuva podatke samo upriimeki čita iz surname. Što se tiče baze podataka, događa se poslednja migracijalast_nameupriimek. Takođe se uklanja ograničenje NOT NULL salast_name. Baza podataka je sada u verzijiv3 - uvoz aplikacije različice
4.0.0— u kodu se ne vrše nikakve izmene. Implementacija baze podatakav4, koja brišelast_name. Ovde možete dodati sve nedostajuće ograničenja u bazu podataka.
Prateći ovaj pristup, uvek možete da se vratite na jednu verziju unazad, ne kršeći kompatibilnost baze podataka / aplikacije.
Код
Sav kod korišćen u ovom članku je dostupan na . Ispod je dodatni opis.
Projekti
Nakon kloniranja repozitorijuma, videćete sledeću strukturu foldera.
├── boot-flyway-v1 - 1.0.0 verzija aplikacije sa v1 šemom
├── boot-flyway-v2 - 2.0.0 verzija aplikacije sa v2 šemom (kompatibilna unazad - aplikaciju je moguće vratiti)
├── boot-flyway-v2-bad - 2.0.0.BAD verzija aplikacije sa v2bad šemom (nekompatibilna unazad - aplikaciju nije moguće vratiti)
├── boot-flyway-v3 - 3.0.0 verzija aplikacije sa v3 šemom (aplikaciju je moguće vratiti)
└── boot-flyway-v4 - 4.0.0 verzija aplikacije sa v4 šemom (aplikaciju je moguće vratiti)Skripti
Možete pokrenuti skripte opisane u donjim skriptama, koje će prikazati unazad kompatibilne i nekompatibilne izmene u bazi podataka.
Da biste videli slučaj sa unazad kompatibilnim izmenama, pokrenite:
.\/scripts\/scenario_backward_compatible.shA da biste videli slučaj sa unazad nekompatibilnim izmenama, pokrenite:
.\/scripts\/scenario_backward_incompatible.shSpring Boot Sample Flyway
Svi primeri su uzeti sa Spring Boot Sample Flyway.
Možete pogledati http://localhost:8080/flyway, tu je lista skripti.
Ovaj primer takođe uključuje H2 konzolu (na adresi http://localhost:8080/h2-console), da biste mogli da pregledate stanje baze podataka (URL jdbc podrazumevano — jdbc:h2:mem:testdb).
Dodatno
Preberite tudi druge članke v našem blogu:
Izvor: habr.com
