Den här artikeln förklarar i detalj hur du löser problem med databaskompatibilitet under driftsättning. Vi kommer att berätta vad som kan hända med dina produktionsapplikationer om du försöker distribuera utan förberedelser. Vi går sedan igenom applikationens livscykelstadier som krävs för att ha noll stilleståndstid (cirka. körfält: vidare - noll stilleståndstid). Resultatet av vår verksamhet blir att tillämpa den bakåtinkompatibla databasändringen på ett bakåtkompatibelt sätt.
Om du vill förstå kodexemplen från artikeln kan du hitta dem på GitHub.
Inledning
Noll driftstopp
Vilken mystisk noll driftstopp? Du kan säga att det är när din applikation distribueras på ett sådant sätt att du framgångsrikt kan introducera en ny version av applikationen till produktion, samtidigt som användaren inte märker dess otillgänglighet. Ur ett användar- och företagsperspektiv är detta det bästa möjliga installationsscenariot eftersom det tillåter att nya funktioner introduceras och buggar kan fixas utan avbrott.
Hur uppnår man detta? Det finns flera sätt, här är ett av dem:
distribuera version nr 1 av din tjänst
utföra en databasmigrering
Distribuera version #2 av din tjänst parallellt med version #1
så fort du ser att version nr 2 fungerar som den ska, ta bort version nr 1
redo!
Lätt, är det inte? Tyvärr är det inte så enkelt, och vi ska titta på det i detalj senare. Låt oss nu kontrollera en annan ganska vanlig distributionsprocess - blågrön implementering.
Har du någonsin hört talas om blågrön utbyggnad? Cloud Foundry gör detta extremt enkelt. Titta bara på denna artikel, där vi beskriver detta mer i detalj. För att kort sammanfatta, låt oss påminna dig om hur du implementerar blågrönt:
se till att två kopior av din produktionskod ("blå" och "grön") fungerar;
styra all trafik till den blå miljön, d.v.s. så att produktionswebbadresser pekar dit;
distribuera och testa alla applikationsändringar i en grön miljö;
byta webbadresser från blå till grön miljö
Blue green distribution är ett tillvägagångssätt som gör att du enkelt kan introducera nya funktioner utan att behöva oroa dig för att produktionen går sönder. Detta beror på det faktum att även om något händer, kan du enkelt rulla tillbaka till den tidigare miljön genom att helt enkelt "snärta på en switch."
Efter att ha läst allt ovanstående kan du ställa frågan: Vad har noll driftstopp att göra med blågrön implementering?
Tja, de har en hel del gemensamt, eftersom att underhålla två exemplar av samma miljö kräver dubbelt arbete för att underhålla dem. Det är därför vissa lag hävdar Martin Fowler, följ en variant av detta tillvägagångssätt:
Ett annat alternativ är att använda samma databas och skapa blågröna växlar för webb- och domänlager. I detta tillvägagångssätt kan databasen ofta vara ett problem, särskilt när du behöver ändra dess schema för att stödja en ny version av programvaran.
Och här kommer vi till huvudproblemet i den här artikeln. databas. Låt oss ta en ny titt på den här frasen.
utföra en databasmigrering.
Nu måste du ställa dig frågan - vad händer om databasändringen inte är bakåtkompatibel? Kommer inte min första version av appen att gå sönder? Det är faktiskt precis vad som kommer att hända...
Så även trots de enorma fördelarna med noll driftstopp/blågrön driftsättning tenderar företag att följa följande säkrare process för att distribuera sina applikationer:
förbereda ett paket med en ny version av programmet
stänga av ett program som körs
kör skript för att migrera databasen
distribuera och starta en ny version av programmet
I den här artikeln beskriver vi hur du kan arbeta med din databas och kod för att dra nytta av driftstopp utan driftstopp.
Databasproblem
Om du har en tillståndslös applikation som inte lagrar några data i databasen, kan du få noll driftstopp direkt. Tyvärr behöver de flesta program lagra data någonstans. Det är därför du bör tänka två gånger innan du gör några ändringar i kretsen. Innan vi går in på detaljerna om hur man ändrar schemat så att driftsättning utan driftstopp är möjlig, låt oss först fokusera på versionsschemat.
Versioneringsschema
I den här artikeln kommer vi att använda Flygväg som ett versionskontrollverktyg (cirka. Översättning: vi pratar om databasmigreringar). Naturligtvis kommer vi också att skriva en Spring Boot-applikation som har inbyggt Flyway-stöd och kommer att utföra schemamigrering samtidigt som applikationskontexten ställs in. När du använder Flyway kan du lagra migreringsskript i din projektmapp (som standard i classpath:db/migration). Här kan du se ett exempel på sådana migreringsfiler
I det här exemplet ser vi 4 migreringsskript som, om de inte har körts tidigare, kommer att köras efter varandra när programmet startar. Låt oss titta på en av filerna (V1__init.sql) som ett exempel.
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');
Allt är helt självförklarande: du kan använda SQL för att definiera hur din databas ska ändras. För mer information om Spring Boot och Flyway, kolla in Spring Boot Docs.
Genom att använda ett källkontrollverktyg med Spring Boot får du två stora fördelar:
du skiljer databasändringar från kodändringar
Databasmigrering sker tillsammans med utrullningen av din applikation, d.v.s. din distributionsprocess förenklas
Felsökning av databasproblem
I nästa avsnitt av artikeln kommer vi att fokusera på att titta på två metoder för databasändringar.
bakåtkompatibilitet
bakåtkompatibilitet
Den första kommer att betraktas som en varning om att du inte bör utföra driftsättning utan driftstopp utan preliminära förberedelser... Den andra erbjuder en lösning på hur du kan utföra en driftsättning utan driftstopp och samtidigt upprätthålla bakåtkompatibilitet.
Vårt projekt vi kommer att arbeta med kommer att vara en enkel Spring Boot Flyway-applikation som har Person с first_name и last_name i databasen (cirka. översättning: Person är ett bord och first_name и last_name - det här är fälten i den). Vi vill byta namn last_name в surname.
Antaganden
Innan vi går in på detaljerna finns det ett par antaganden vi måste göra om våra applikationer. Huvudresultatet vi vill uppnå kommer att vara en ganska enkel process.
Anteckningen. Business PRO-TIPS. Genom att förenkla processer kan du spara mycket pengar på support (ju fler personer du har som arbetar för ditt företag, desto mer pengar kan du spara)!
Du behöver inte återställa databasen
Detta förenklar distributionsprocessen (vissa databasåterställningar är nästan omöjliga, till exempel återställning av borttagning). Vi föredrar att endast återställa applikationer. På så sätt, även om du har olika databaser (till exempel SQL och NoSQL), kommer din distributionspipeline att se likadan ut.
Det måste ALLTID vara möjligt att återställa applikationen en version tillbaka (inte mer)
Återställning bör endast göras vid behov. Om det finns en bugg i den aktuella versionen som inte är lätt att fixa, bör vi kunna återgå till den senaste fungerande versionen. Vi antar att den senaste fungerande versionen är den tidigare. Att upprätthålla kod- och databaskompatibilitet för mer än en utrullning skulle vara extremt svårt och dyrt.
Anteckningen. För större läsbarhet kommer vi i den här artikeln att ändra huvudversionen av applikationen.
Steg 1: Ursprungligt tillstånd
Appversion: 1.0.0
DB version: v1
Kommentar
Detta kommer att vara det ursprungliga tillståndet för ansökan.
Databasförändringar
DB innehåller 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');
Kodändringar
Applikationen lagrar personuppgifter i 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
+ "]";
}
}
Bakåt inkompatibel kolumnbyte
Låt oss titta på ett exempel på hur man ändrar ett kolumnnamn:
Uppmärksamhet. Följande exempel kommer avsiktligt att bryta saker. Vi visar detta för att visa problemet med databaskompatibilitet.
Appversion: 2.0.0.BAD
DB version: v2bad
Kommentar
De nuvarande ändringarna tillåter INTE att vi kör två instanser (gamla och nya) samtidigt. Således kommer noll driftstopp att vara svår att uppnå (om man tar hänsyn till antaganden är det faktiskt omöjligt).
A/B-testning
Den nuvarande situationen är att vi har en applikationsversion 1.0.0, distribueras i produktion och databas v1. Vi måste distribuera en andra instans av applikationen, version 2.0.0.BADoch uppdatera databasen till v2bad.
steg:
en ny instans av versionsapplikationen distribueras 2.0.0.BADsom uppdaterar databasen till v2bad
i databasen v2bad kolumn last_name finns inte längre - det ändrades till surname
Uppdateringen av databasen och applikationen lyckades och vissa instanser körs 1.0.0, andra - in 2.0.0.BAD. Allt är kopplat till databasen v2bad
alla instanser av versionen 1.0.0 kommer att börja skicka fel eftersom de kommer att försöka infoga data i kolumnen last_namesom inte längre finns
alla instanser av versionen 2.0.0.BAD kommer att fungera utan problem
Som du kan se, om vi gör bakåtinkompatibla ändringar i databasen och applikationen, är A/B-testning omöjlig.
Återställning av ansökan
Låt oss anta att efter att ha försökt göra A/B-distribution (cirka. per.: författaren menade förmodligen A/B-testning här) beslutade vi att vi måste återställa applikationen till versionen 1.0.0. Låt oss säga att vi inte vill återställa databasen.
steg:
vi stoppar versionsapplikationsinstansen 2.0.0.BAD
databasen är stilla v2bad
sedan versionen 1.0.0 förstår inte vad det är surname, vi kommer att se fel
helvetet har brutit lös, vi kan inte gå tillbaka längre
Som du kan se, om vi gör bakåt inkompatibla ändringar i databasen och applikationen, kan vi inte återgå till den tidigare versionen.
Skriptkörningsloggar
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"}
Databasförändringar
Migreringsskript som byter namn last_name в surname
Källa Flyway-skript:
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 som byter namn last_name.
-- This change is backward incompatible - you can't do A/B testing
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;
Kodändringar
Vi har ändrat fältnamnet lastName på surname.
Byta namn på en kolumn på ett bakåtkompatibelt sätt
Detta är den vanligaste situationen vi kan stöta på. Vi måste göra bakåt inkompatibla förändringar. Vi har redan bevisat att för driftsättning utan driftstopp bör vi inte bara tillämpa databasmigrering utan ytterligare steg. I det här avsnittet av artikeln kommer vi att utföra 3 distributioner av applikationen tillsammans med databasmigreringar för att uppnå önskat resultat med bibehållen bakåtkompatibilitet.
Anteckningen. Kom ihåg att vi har en versionsdatabas v1. Den innehåller kolumner first_name и last_name. Vi måste ändra oss last_name på surname. Vi har även appversion 1.0.0, som ännu inte används surname.
Steg 2: Lägg till efternamn
Appversion: 2.0.0
DB version: v2
Kommentar
Genom att lägga till en ny kolumn och kopiera dess innehåll skapar vi bakåtkompatibla databasändringar. Samtidigt, om vi rullar tillbaka JAR eller har en gammal JAR igång, kommer den inte att gå sönder under körningen.
Vi rullar ut en ny version
steg:
utföra en databasmigrering för att skapa en ny kolumn surname. Nu din DB-version v2
kopiera data från last_name в surname. Observeraatt om du har mycket av denna data bör du överväga batchmigrering!
skriv koden där de används BÅDE и nyOch den gamla kolumn. Nu din appversion 2.0.0
läs värdet från kolumnen surname, om det inte är det null, eller från last_nameom surname ej angivet. Du kan ta bort getLastName() från koden, eftersom den kommer att matas ut null när du återställer din ansökan från 3.0.0 до 2.0.0.
Om du använder Spring Boot Flyway kommer dessa två steg att utföras under versionsstart 2.0.0 applikationer. Om du kör verktyget för databasversionering manuellt måste du göra två olika saker för att göra detta (först uppdatera db-versionen manuellt och sedan distribuera den nya applikationen).
Det är viktigt. Kom ihåg att den nyskapade kolumnen BORDE INTE быть INTE NULL. Om du gör en återställning känner den gamla applikationen inte till den nya kolumnen och kommer inte att installera den under Insert. Men om du lägger till denna begränsning så blir din db v2, detta kräver att värdet för den nya kolumnen ställs in. Vilket kommer att leda till överträdelser av restriktioner.
Det är viktigt. Du bör ta bort metoden getLastName(), eftersom i versionen 3.0.0 Det finns inget koncept för en kolumn i koden last_name. Det betyder att null kommer att sättas där. Du kan lämna metoden och lägga till kontroller för null, men en mycket bättre lösning skulle vara att se till det i logiken getSurname() du valde rätt värde som inte är noll.
A/B-testning
Den nuvarande situationen är att vi har en applikationsversion 1.0.0, distribueras på produktion, och databasen i v1. Vi måste distribuera en andra instans av versionsapplikationen 2.0.0som kommer att uppdatera databasen till v2.
steg:
en ny instans av versionsapplikationen distribueras 2.0.0som uppdaterar databasen till v2
under tiden behandlades vissa förfrågningar av versionsinstanser 1.0.0
uppdateringen lyckades och du har flera körande instanser av versionsapplikationen 1.0.0 och andra versioner 2.0.0. Alla kommunicerar med databasen i v2
version 1.0.0 använder inte efternamnskolumnen i databasen, utan versionen 2.0.0 använder. De stör inte varandra, och det bör inte finnas några fel.
version 2.0.0 lagrar data i både den gamla och nya kolumnen, vilket säkerställer bakåtkompatibilitet
Det är viktigt. Om du har några frågor som räknar objekt baserat på värden från den gamla/nya kolumnen, bör du komma ihåg att du nu har dubbletter av värden (mest troligt migrerar de fortfarande). Till exempel, om du vill räkna antalet användare vars efternamn (vad kolumnen heter) började med bokstaven A, sedan tills datamigreringen är klar (old → new kolumn) kan du ha inkonsekventa data om du frågar efter en ny kolumn.
Återställning av ansökan
Nu har vi appversion 2.0.0 och databas i v2.
steg:
rulla tillbaka din applikation till version 1.0.0.
version 1.0.0 använder inte en kolumn i databasen surname, så återställningen bör vara framgångsrik
DB ändringar
Databasen innehåller en kolumn med namnet last_name.
Flyway källskript:
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');
Lägg till skript surname.
Uppmärksamhet. Kom ihåg att du INTE KAN LÄGG TILL NÅGRA NOT NULL-begränsningar i kolumnen du lägger till. Om du återställer JAR kommer den gamla versionen inte att ha någon aning om den tillagda kolumnen och kommer automatiskt att ställa in den på NULL. Om det finns en sådan begränsning kommer den gamla applikationen helt enkelt att gå sönder.
-- 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
Kodändringar
Vi lagrar data som last_name, och i surname. Samtidigt läser vi från last_name, eftersom den här kolumnen är den mest relevanta. Under distributionsprocessen kan vissa förfrågningar ha behandlats av en applikationsinstans som ännu inte har uppdaterats.
/*
* 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
+ "]";
}
}
Steg 3: Ta bort efternamn från koden
Appversion: 3.0.0
DB version:v3
Kommentar
Notera per.: Tydligen, i den ursprungliga artikeln kopierade författaren av misstag texten i detta block från steg 2. I detta steg bör ändringar göras i applikationskoden som syftar till att ta bort funktionaliteten som använder kolumnen last_name.
Genom att lägga till en ny kolumn och kopiera dess innehåll skapade vi bakåtkompatibla databasändringar. Dessutom, om vi återställer JAR eller har en gammal JAR igång, kommer den inte att gå sönder under körningen.
Återställning av ansökan
För närvarande har vi appversion 3.0.0 och databas v3. Version 3.0.0 sparar inte data till last_name. Det betyder att i surname den mest uppdaterade informationen lagras.
steg:
rulla tillbaka din applikation till version 2.0.0.
version 2.0.0 använder och last_name и surname.
version 2.0.0 ska ta surname, om det inte är noll, annars -last_name
Databasförändringar
Det finns inga strukturella förändringar i databasen. Följande skript körs för att utföra den slutliga migreringen av gamla data:
-- 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;
Kodändringar
Notera per.: Beskrivningen av detta block kopierades också av misstag av författaren från steg 2. I enlighet med artikelns logik bör ändringar i koden i detta steg syfta till att ta bort element från den som fungerar med kolumnen last_name.
Vi lagrar data som last_name, och i surname. Dessutom läser vi från spalten last_name, eftersom det är det mest relevanta. Under distributionsprocessen kan vissa förfrågningar behandlas av en instans som ännu inte har uppgraderats.
/*
* 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
+ "]";
}
}
Steg 4: Ta bort efternamn från databasen
Appversion: 4.0.0
DB version: v4
Kommentar
På grund av det faktum att versionskoden 3.0.0 använde inte kolumnen last_name, inget dåligt kommer att hända under utförandet om vi rullar tillbaka till 3.0.0 efter att ha tagit bort en kolumn från databasen.
Skriptkörningsloggar
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 ändringar
om v3 vi tar bara bort kolumnen last_name och lägg till begränsningar som saknas.
-- 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;
Kodändringar
Det finns inga ändringar i koden.
Utgång
Vi har tillämpat en bakåtinkompatibel kolumnnamnsändring genom att utföra flera bakåtkompatibla distributioner. Nedan följer en sammanfattning av de åtgärder som utförts:
distribution av applikationsversion 1.0.0 с v1 databasschema (kolumnnamn = last_name)
distribution av applikationsversion 2.0.0, som lagrar data i last_name и surname. Ansökan läser från last_name. Databasen finns i version v2som innehåller kolumner som last_name, och surname. surname är en kopia av last_name. (OBS: Denna kolumn får inte ha en noll-begränsning)
distribution av applikationsversion 3.0.0, som endast lagrar data i surname och läser från efternamn. När det gäller databasen pågår den senaste migreringen last_name в surname. Också en begränsning INTE NULL borttagen från last_name. Databasen är nu i version v3
distribution av applikationsversion 4.0.0 - inga ändringar görs i koden. Databasdistribution v4, som tar bort last_name. Här kan du lägga till eventuella saknade begränsningar till databasen.
Genom att följa detta tillvägagångssätt kan du alltid återställa en version utan att bryta databas-/applikationskompatibiliteten.
Kod
All kod som används i den här artikeln är tillgänglig på Github. Nedan finns ytterligare beskrivning.
Projekt
Efter att ha klonat förvaret kommer du att se följande mappstruktur.
├── 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)
Manus
Du kan köra skripten som beskrivs i skripten nedan, som kommer att visa bakåtkompatibla och inkompatibla ändringar i databasen.
Att se fallet med bakåtkompatibla ändringar, springa:
./scripts/scenario_backward_compatible.sh
Och att se fall med bakåt inkompatibla ändringar, springa:
./scripts/scenario_backward_incompatible.sh
Spring Boot Sample Flyway
Alla exempel är hämtade från Spring Boot Sample Flyway.
Du kan ta en titt på http://localhost:8080/flyway, det finns en lista med skript.
Detta exempel inkluderar även H2-konsolen (at http://localhost:8080/h2-console) så att du kan se databasstatus (standard jdbc URL är jdbc:h2:mem:testdb).