
Ky this article explains in detail how to resolve database compatibility issues during deployment. We will explain what can happen to your applications in production if you attempt a deployment without prior preparation. Then we will go through the stages of the application lifecycle needed for zero downtime (note: subsequently — zero downtime). The result of our operations will be the application of a back-incompatible database change in a backward-compatible way.
If you want to understand the code examples from the article, you can find them at .
Hyrje
Zero downtime deployment
What is this mystical zero downtime deployment? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.
How to achieve it? There are several ways, here is one of them:
- deploy version #1 of your service
- migrate the DB
- deploy version #2 of your service alongside version #1
- as soon as you see that version #2 is working as it should, remove version #1
- done!
Easy, right? Unfortunately, it's not that simple, and we'll discuss this in detail later. But for now, let's check another fairly common deployment process — blue green deployment.
Have you ever heard of ? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на , where we describe this in more detail. In short, let’s summarize how to perform blue green deployment:
- ensure two copies of your production code are running (“blue” and “green”);
- direct all traffic to the blue environment, i.e., that the production URLs point there;
- deploy and test all application changes in the green environment;
- switch the URLs from the blue to the green environment
Blue green deployment is an approach that allows you to easily introduce new features without worrying that production will break. This is due to the fact that even if something goes wrong, you can easily roll back to the previous environment by simply 'flipping a switch'.
After reading all the above, you might ask the question: What does zero downtime have to do with blue green deployment?
Well, they have quite a lot in common, as maintaining two copies of the same environment requires double the effort to manage them. That's why some teams, as stated by , adhere to a variation of this approach:
një alternativë tjetër është të përdorim të njëjtën bazë të dhënash, duke krijuar kalime blu-të gjelbra për web dhe domain layers. Në këtë qasje, bazat e të dhënave shpesh mund të jenë problematike, veçanërisht kur ju nevojitet të ndryshoni skemën e saj për të mbështetur një version të ri të softuerit.
Këtu kemi arritur në problemin kryesor të këtij artikulli. Baza e të dhënave. Le të shohim përsëri këtë frazë.
kryeni migrimin e bazës së të dhënave.
Tani duhet t'i bëni vetes një pyetje — çfarë, nëse ndryshimi i bazës së të dhënave është prapa jo kompatibel? A do të thyhet versioni im i parë i aplikacionit? Në të vërtetë, kjo do të ndodhte...
Kështu, edhe pse përfitimet e zero downtime / blue green deployment janë të mëdha, kompanitë tendencojnë të ndjekin procesin më të sigurt për të zhvilluar aplikacionet e tyre:
- preparoni një paketë me versionin e ri të aplikacionit
- ndaloni aplikacionin e lançuar
- ekzekutoni skemat për migrimin e bazës së të dhënave
- zhvilloni dhe lançoni versionin e ri të aplikacionit
Në këtë artikull do të përshkruajmë në detaje se si mund të punoni me bazën e të dhënave dhe kodin, për të shfrytëzuar përfitimet e zero downtime deployment.
Problemet me bazën e të dhënave
Nëse keni një aplikacion stateless që nuk ruan të dhëna në bazën e të dhënave, mund të merrni zero downtime deployment menjëherë. Fatkeqësisht, pjesa më e madhe e softuerit ka nevojë të ruajë të dhëna diku. Kjo është arsyeja pse duhet ta mendoni dy herë para se të bëni ndonjë ndryshim në skemë. Para se të thellohemi në detajet se si të ndryshoni skemën në një mënyrë që të bëhet e mundur zhvillimi pa ndalesa, le të fokusohemi së pari në skemën e menaxhimit të versioneve.
Skema e menaxhimit të versioneve
Në këtë artikull ne do të përdorim si një mjet për menaxhimin e versioneve (shën. red.: bëhet fjalë për migrimet e bazës së të dhënave). Natyrisht, ne gjithashtu do të shkruajmë një aplikacion Spring Boot, i cili ka mbështetje të integruar për Flyway dhe do të kryejë migrimin e skemës gjatë konfigurimit të kontekstit të aplikacionit. Duke përdorur Flyway, mund të ruani skemat e migrimit në dosjen e projekteve tuaja (në mënyrë të paracaktuar në classpath:db/migration). Këtu mund të shihni një shembull të tillë të skemave të migrimit
└── db
└── migration
├── V1__init.sql
├── V2__Add_surname.sql
├── V3__Final_migration.sql
└── V4__Remove_lastname.sqlNë këtë shembull ne shohim 4 skenarë migrimi, të cilët, nëse nuk janë realizuar më parë, do të kryhen një pas një gjatë aktivizimit të aplikacionit. Le të shqyrtojmë një nga skedarët (V1__init.sql) si shembull.
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');Të gjitha flasin qartë për veten: mund të përdorni SQL për të përcaktuar si duhet të ndryshohet baza juaj e të dhënave. Për më shumë informacion mbi Spring Boot dhe Flyway, shikoni .
Duke përdorur një mjet menaxhimi versioni me Spring Boot, ju fitoni 2 përfitime të mëdha:
- ju ndan ndryshimet e bazës së të dhënave nga ndryshimet e kodit
- migrimi i bazës së të dhënave ndodh së bashku me lançimin e aplikacionit tuaj, dmth. procesi juaj i deploy-it thjeshtohet
Zgjidhja e problemeve me bazën e të dhënave
Në seksionin e ardhshëm të artikullit, ne do të përqendrohemi në shqyrtimin e dy qasjeve për ndryshimet në bazën e të dhënave.
- mośpajtimi kthyes
- mośpajtimi i kaluar
E para do të shqyrtohet si një paralajmërim, që nuk duhet të realizoni deploy me zero downtime pa përgatitje paraprake… E dyta ofron një zgjidhje se si mund të realizoni deploy pa ndalesa dhe njëkohësisht të mbani mośpajtimin e kaluar.
Projekti ynë, mbi të cilin do të punojmë, do të jetë një aplikacion i thjeshtë Spring Boot Flyway, në të cilin ka Person me first_name dhe last_name në bazën e të dhënave (shënim i përkthyesit: Person është tabela, dhe first_name dhe last_name është fushë në të). Ne duam ta riemërtojmë last_name në surname.
Supozimet
Para se të thellohemi në detaje, është e nevojshme të shënojmë disa supozime lidhur me aplikacionet tona. Rezultati kryesor që dëshirojmë të arrijmë do të jetë një proces mjaft i thjeshtë.
Shënim. Këshillë profesionale. Thjeshtimi i proceseve mund t'ju kursejë shumë para për mbështetje (sa më shumë njerëz të punojnë në kompaninë tuaj, aq më shumë para mund të kurseni)!
Nuk duhet të bëni rikthim të bazës së të dhënave
Kjo e thjeshton procesin e deploy-it (disa rikthime të bazës së të dhënave janë praktikisht të pamundura, për shembull rikthimi i fshirjes). Ne preferojmë të rikthejmë vetëm aplikacionet. Kështu, edhe nëse keni baza të dhënash të ndryshme (për shembull, SQL dhe NoSQL), pipeline-i juaj i deploy-it do të duket njëshe.
Duhet që gjithmonë të ketë mundësi për të rikthyer aplikacionin një version mbrapa (jo më shumë)
Rikthimi duhet të bëhet vetëm në rast nevoje. Nëse versioni aktual ka një gabim që është i vështirë për t'u rregulluar, ne duhet të jemi në gjendje të kthehemi në versionin e fundit funksional. Ne supzojmë se ky version i fundit funksional është versioni paraprak. Mbështetja e kompatibilitetit të kodit dhe të dhënave për më shumë se një version të nxjerrë do të ishte jashtëzakonisht e vështirë dhe e shtrenjtë.
Shënim. Për më shumë lexueshmëri, brenda këtij artikulli ne do të ndryshojmë versionin kryesor të aplikacionit.
Hapi 1: Gjendja fillestare
Versioni i aplikacionit: 1.0.0
Versioni i DB: v1
Koment
Kjo do të jetë gjendja fillestare e aplikacionit.
Ndryshimet e DB
DB përmban 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');Ndryshimet e kodit
Aplikacioni ruan të dhënat e Person në 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
+ "]";
}
}Rinovimi jo-kompatibil i kolonës
Le të shqyrtojmë një shembull se si të ndryshojmë emrin e kolonës:
Kujdes. Shembulli në vazhdim do të çojë qëllimisht në dështim. Ne e tregojmë këtë për të demonstruar problemin e kompatibilitetit të bazës së të dhënave.
Versioni i aplikacionit: 2.0.0.BAD
Versioni i DB: v2bad
Koment
Ndryshimet aktuale NUK na lejojnë të ekzekutojmë dy ekzemplarë (të vjetër dhe të ri) në të njëjtën kohë. Kështu, zbatimi pa ndalesa do të jetë i vështirë për t'u arritur (nëse marrim parasysh supozimet, në fakt është e pamundur).
A/B testimi
Situata aktuale është se kemi një aplikacion versioni 1.0.0, të vendosur në prodhim, dhe DB v1. Ne duhet të vendosim një ekzemplar të dytë të aplikacionit, versioni 2.0.0.BAD, dhe të përmirësojmë bazën e të dhënave deri në v2bad.
Hapat:
- ka shpërndarë një ekzemplar të ri të aplikacionit versioni
2.0.0.BAD, i cili përmirëson bazën e të dhënave deri nëv2bad - në bazën e të dhënave
v2badkolonalast_namenuk ekziston më — është ndryshuar nësurname - përmirësimi i bazës së të dhënave dhe aplikacionit kaloi me sukses, dhe disa ekzemplarë funksionojnë në
1.0.0, të tjerët — në2.0.0.BAD. Të gjithë janë të lidhur me DBv2bad - të gjithë ekzemplarët e versionit
1.0.0do të fillojnë të japin gabime, sepse ata do të përpiqen të futin të dhëna në kolonënlast_name, e cila nuk ekziston më - të gjithë ekzemplarët e versionit
2.0.0.BADdo të funksionojnë pa probleme
Siç e shihni, nëse ne bëjmë ndryshime jo-kompatibile në DB dhe aplikacion, A/B testimi është e pamundur.
Rikthimi i aplikacionit
Le të supozojmë se pas përpjekjes për të kryer një zbatim A/B (shënim i përkthyesit: ndoshta këtu autori kishte në mendje A/B testimin) ne vendosëm se na nevojitet të rikthejmë aplikacionin në versionin 1.0.0. Supozoni se nuk duam të bëjmë rikthimin e bazës së të dhënave.
Hapat:
- ndalojmë instancën e aplikacionit versioni
2.0.0.BAD - bazën e të dhënave akoma
v2bad - sepse versioni
1.0.0nuk e kupton se çfarë ështësurname, do të shohim gabime - demonët janë liruar, nuk mund të kthehemi më
Siç e shihni, nëse bëjmë ndryshime të pa kompatibilitetit në DB dhe aplikacion, ne nuk mund të kthehemi në versionin e mëparshëm.
Logët e ekzekutimit të skriptit
Skenari i pa kompatibilitetit:Ndryshimet e DB
Skripti i migrimit, i cili rinomin last_name në surname
Skripti origjinal i 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');Skripti, i cili rinomin last_name.
-- Ky ndryshim është i pa kompatibilitet - nuk mund të bëni testim A/B
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;Ndryshimet e kodit
Ne kemi ndryshuar emrin e fushës lastName në surname.
Rinomin e kolonës në një mënyrë të pa kompatibilitet
Kjo është situata më e zakonshme me të cilën ne mund të përballeshim. Na nevojitet të bëjmë ndryshime të pa kompatibilitet. Ne kemi dëshmuar tashmë se për të kryer një ndarje pa ndërprerje, ne nuk duhet thjesht të aplikojmë migrimin e të dhënave pa veprime shtesë. Në këtë seksion të artikullit do të kryejmë 3 ndarje të aplikacionit së bashku me migrimet e të dhënave, për të arritur rezultatet e dëshiruara dhe gjithashtu për të ruajtur kompatibilitetin e anashtuar.
Shënim. Të kujtojmë se kemi DB versioni
v1. Ajo përmban kolonafirst_namedhelast_name. Ne duhet të ndryshojmëlast_namenësurname. Po ashtu kemi aplikacion në versionin1.0.0,i cili akoma nuk e përdorsurname.
Hapi 2: Shto surname
Versioni i aplikacionit: 2.0.0
Versioni i DB: v2
Koment
Duke shtuar një kolonë të re dhe duke kopjuar përmbajtjen e saj, ne krijojmë ndryshime të pa kompatibilitetit të DB. Në të njëjtën kohë, nëse kthejmë JAR-in ose kemi një JAR të vjetër që punon, ai nuk do të dështojë gjatë ekzekutimit.
Nxjerrim versionin e ri
Hapat:
- kryeni migrimin e DB për të krijuar kolonën e re
surname. Tani DB juaj i versionitv2 - kopjoni të dhënat nga
last_namenësurname. Vini re, çka nëse keni shumë nga këto të dhëna, duhet të merrni në konsideratë migrimin me paketë! - shkruani kodin, ku përdoren TË DY dhe i ri, dhe të vjetra kolona. Tani tani aplikacioni i juaj version
2.0.0 - lexoni vlerën nga kolona
surname, nëse ajo nuknull, apo nga last_name, nësesurnamenuk është caktuar. Ju mund të hiqnigetLastName()nga kodi, pasi ai do të japënullnë rastin e rikthimit të aplikacionit tuaj nga3.0.0në2.0.0.
Nëse po përdorni Spring Boot Flyway, këto dy hapa do të realizohen gjatë nisjes së versionit 2.0.0 të aplikacionit. Nëse e nisni mjetin e menaxhimit të versioneve të bazës së të dhënave manualisht, do t'ju duhet të bëni dy veprime të ndryshme për këtë (së pari përditësoni manualisht versionin e db-së dhe pastaj implementoni aplikacionin e ri).
E rëndësishme. Mos harroni se kolona e re e krijuar NUK DUHET të jesh NOT NULL. Nëse bëni rikthim, aplikacioni i vjetër nuk di për kolonën e re dhe nuk do ta vendosë atë gjatë
Insert.Por nëse e shtoni këtë kufizim, dhe DB-ja juaj do tëv2, do të kërkojë caktimin e vlerës së kolonës së re. Kjo do të çojë në shkelje të kufizimeve.E rëndësishme. Duhet të hiqni metodën
getLastName(), pasi në versionin3.0.0në kod nuk ka konceptin e kolonëslast_name. Kjo do të thotë që atje do të vendosen null. Ju mund ta lini metodën dhe të shtoni kontrolle përnull, por një zgjidhje më e mirë do të ishte të siguroni që në logjikëngetSurname()kur zgjidhni vlerën e duhur të paprikë.
A/B testimi
Situata aktuale është se kemi një aplikacion versioni 1.0.0, e implementuar në prodhim, dhe DB-ja në v1. Ne duhet të implementojmë një ekzemplar të dytë të versionit të aplikacionit 2.0.0, i cili do të përditësojë bazën e të dhënave deri në v2.
Hapat:
- ka shpërndarë një ekzemplar të ri të aplikacionit versioni
2.0.0, i cili përmirëson bazën e të dhënave deri nëv2 - ndërkohë disa kërkesa u përpunuan nga ekzemplarët e versionit
1.0.0 - përditësimi kaloi me sukses, dhe keni disa ekzemplarë funksionalë të aplikacionit të versionit
1.0.0dhe versionet e tjera2.0.0.Të gjitha komunikojnë me DB-në nëv2 - i
1.0.0nuk përdor në DB kolonën e mbiemrit, ndërsa versioni2.0.0e përdor. Ato nuk e pengojnë njëra-tjetrën, dhe nuk duhet të ketë gabime. - i
2.0.0ruan të dhënat si në kolonën e vjetër ashtu edhe në atë të re, duke siguruar kështu përputhshmërinë prapavepruese
E rëndësishme. Nëse keni ndonjë kërkesë që numëron elementet në bazë të vlerave nga kolona e vjetër / e re, duhet të mbani mend se tani keni dyfishim të vlerave (më shumë se një herë mund të jenë ende në migrim). Për shembull, nëse dëshironi të llogaritni numrin e përdoruesve, emri i mbiemrit (pavarësisht si e quani kolonën) fillonte me shkronjën
A, atëherë deri në përfundimin e migrimit të të dhënave (old→të rejakolona) mund të keni të dhëna jo konsistente, nëse ekzekutoni një kërkesë në kolonën e re.
Rikthimi i aplikacionit
Tani kemi aplikacionin e versionit 2.0.0 dhe bazën e të dhënave në v2.
Hapat:
- ktheni aplikacionin tuaj në versionin
1.0.0. - i
1.0.0nuk përdor në DB kolonënsurname, prandaj rikthimi duhet të jetë i suksesshëm
Ndryshimet DB
DB përmban një kolonë me emrin last_name.
Skedari burimor 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');Skedari i shtimit surname.
Kujdes. Kujtoni se nuk DUHET të SHTOhen asnjë kufizim NOT NULL në kolonën e shtuar. Nëse e riktheni JAR-in, versioni i vjetër nuk do të ketë njohuri për kolonën e shtuar dhe do t'i caktojë automatikisht vlerën NULL. Nëse ka një kufizim të tillë, aplikacioni i vjetër do të prishet.
-- VËREJTJE: Ky fushë nuk mund të ketë kufizimin NOT NULL sepse nëse e riktheni, versioni i vjetër nuk do të dijë për këtë fushë
-- dhe do ta caktojë gjithmonë në NULL
ALTER TABLE PERSON ADD surname varchar(255);
-- NE PO SUPOZONIMI QË ËSHTË NJË MIGRIM I SHPEJTË - ND otherwise DO TË DUHEJ TË MIGRONIM NË GRUPE
UPDATE PERSON SET PERSON.surname = PERSON.last_nameNdryshimet e kodit
Ne ruajmë të dhënat si në last_name, ashtu edhe në surname. Ndërkohë lexojmë nga last_name, sepse kjo kolonë është më e rëndësishmja. Gjatë procesit të shpërndarjes, disa pyetje mund të jenë trajtuar nga një instancë aplikacioni që nuk është përditësuar ende.
/*
* 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
+ "]";
}
}Hapi 3: Heqja e last_name nga kodi
Versioni i aplikacionit: 3.0.0
Versioni i DB:v3
Koment
Shënim: Duket se në artikullin origjinal autori gabimisht kopjoi tekstin e këtij blloku nga hapi 2. Në këtë hap, duhet bërë ndryshime në kodin e aplikacionit për të hequr funksionalitetin që përdor kolonën last_name.
Duke shtuar një kolonë të re dhe duke kopjuar përmbajtjen e saj, krijuam ndryshime të përputhshme me versionet e mëparshme të DB. Gjithashtu, nëse e rikthejmë JAR-in ose kemi një JAR të vjetër që funksionon, ai nuk do të prishet gjatë ekzekutimit.
Rikthimi i aplikacionit
Aktualisht kemi një aplikacion versioni 3.0.0 dhe një bazë të dhënash v3. Versioni 3.0.0 nuk ruan të dhënat në last_name. Kjo do të thotë se në surname ruhet informacioni më i fundit.
Hapat:
- ktheni aplikacionin tuaj në versionin
2.0.0. - i
2.0.0përdor dhelast_namedhesurname. - i
2.0.0do të marrësurname, nëse ai nuk është NULL, përndryshe —last_name
Ndryshimet e DB
Nuk ka ndryshime strukturore në DB. Po ekzekutohet skedari i mëposhtëm që bën migrimin përfundimtar të të dhënave të vjetra:
-- NE PO SUPOZONIMI QË ËSHTË NJË MIGRIM I SHPEJTË - NË RASHT SE KJO DO TË DUHET TË MIGRONIM NË GRUPE
-- PO ASNJËHERË NUK JEMI TË SIGURT NËSE NUK JEMI DUKE KALUAR HULLORE DHE PËRMBAJTJE EKZISTUESE. DUHET TË KOMPAROJMË
-- VERSIONE TË HULLORE TË SIGURIMI QË NËSE KA NJË HULLOR ME NJË NUMËR VERSIONI MË TË LARTË
-- NE NUK DO TË KALUARIMË
UPDATE PERSON SET PERSON.surname = PERSON.last_name;
-- HEQJA E KUFIZIMIT NOT NULL; PËNDYSH SE DO TË PROVOJMË TË SHTOJMË VLERË NULL TË LAST_NAME
-- ME NJË KUFIZIM NOT NULL.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;Ndryshimet e kodit
Shënim: Përshkrimi i këtij blloku gjithashtu u kopjua gabimisht nga autori nga hapi 2. Sipas logjikës së tregimit të artikullit, ndryshimet në kodin në këtë hap duhet të jenë të orientuara për të hequr elementët që punojnë me kolonën last_name.
Ne ruajmë të dhënat si në last_name, ashtu edhe në surname. Për më tepër, ne lexojmë nga kolona last_name, pasi është më relevante. Gjatë procesit të shpërndarjes, disa kërkesa mund të trajtohen nga një instancë që ende nuk është azhurnuar.
/*
* 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
+ "]";
}
}Hapi 4: Fshirja e last_name nga DB
Versioni i aplikacionit: 4.0.0
Versioni i DB: v4
Koment
Për shkak se kodi version 3.0.0 nuk përdori kolonën last_name, gjatë ekzekutimit nuk do të ndodhë asgjë e keqe nëse rikthemi në 3.0.0 pas fshirjes së kolonës nga baza e të dhënave.
Logët e ekzekutimit të skriptit
Ne do ta bëjmë në mënyrën e mëposhtme:
01) Ekzekuto 1.0.0
02) Prisni që aplikacioni (1.0.0) të boot-ojë
03) Gjeneroni një person duke thirrur POST localhost:9991/person për versionin 1.0.0
04) Ekzekuto 2.0.0
05) Prisni që aplikacioni (2.0.0) të boot-ojë
06) Gjeneroni një person duke thirrur POST localhost:9991/person për versionin 1.0.0
07) Gjeneroni një person duke thirrur POST localhost:9992/person për versionin 2.0.0
08) Vrit aplikacionin (1.0.0)
09) Ekzekuto 3.0.0
10) Prisni që aplikacioni (3.0.0) të boot-ojë
11) Gjeneroni një person duke thirrur POST localhost:9992/person për versionin 2.0.0
12) Gjeneroni një person duke thirrur POST localhost:9993/person për versionin 3.0.0
13) Vrit aplikacionin (3.0.0)
14) Ekzekuto 4.0.0
15) Prisni që aplikacioni (4.0.0) të boot-ojë
16) Gjeneroni një person duke thirrur POST localhost:9993/person për versionin 3.0.0
17) Gjeneroni një person duke thirrur POST localhost:9994/person për versionin 4.0.0
Duke nisur aplikacionin në versionin 1.0.0
Gjeneroni një person në versionin 1.0.0
Dërgimi i një postimi në 127.0.0.1:9991/person. Kjo është përgjigjja:
{"firstName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2","lastName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2"}
Duke nisur aplikacionin në versionin 2.0.0
Gjeneroni një person në versionin 1.0.0
Dërgimi i një postimi në 127.0.0.1:9991/person. Kjo është përgjigjja:
{"firstName":"e41ee756-4fa7-4737-b832-e28827a00deb","lastName":"e41ee756-4fa7-4737-b832-e28827a00deb"}
Gjeneroni një person në versionin 2.0.0
Dërgimi i një postimi në 127.0.0.1:9992/person. Kjo është përgjigjja:
{"firstName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","lastName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","surname":"0c1240f5-649a-4bc5-8aa9-cff855f3927f"}
Duke vrarë aplikacionin 1.0.0
Duke nisur aplikacionin në versionin 3.0.0
Gjeneroni një person në versionin 2.0.0
Dërgimi i një postimi në 127.0.0.1:9992/person. Kjo është përgjigjja:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}
Gjeneroni një person në versionin 3.0.0
Dërgimi i një postimi në 127.0.0.1:9993/person. Kjo është përgjigjja:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}
Duke vrarë aplikacionin 2.0.0
Duke nisur aplikacionin në versionin 4.0.0
Gjeneroni një person në versionin 3.0.0
Dërgimi i një postimi në 127.0.0.1:9993/person. Kjo është përgjigjja:
{"firstName":"cbe942fc-832e-45e9-a838-0fae25c10a51","surname":"cbe942fc-832e-45e9-a838-0fae25c10a51"}
Gjeneroni një person në versionin 4.0.0
Dërgimi i një postimi në 127.0.0.1:9994/person. Kjo është përgjigjja:
{"firstName":"ff6857ce-9c41-413a-863e-358e2719bf88","surname":"ff6857ce-9c41-413a-863e-358e2719bf88"}Ndryshimet e DB
Sa i përket v3 ne thjesht po fshijmë kolonën last_name dhe po shtojmë kufizimet e munguar.
-- FSHI KOLONËN
ALTER TABLE PERSON DROP last_name;
-- SHTO KUFIZIMET
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;Ndryshimet e kodit
Nuk ka ndryshime në kod.
Përfundimi
Ne e aplikuam me sukses ndryshimin e paqartë të emrit të kolonës duke realizuar disa shpërndarje të kthyeshme. Më poshtë është një përmbledhje e veprimeve të kryera:
- shpërndarjen e aplikacionit në versionin
1.0.0mev1skemat e DB (emri i kolonës =last_name) - shpërndarjen e aplikacionit në versionin
2.0.0,e cila ruan të dhënat nëlast_namedhesurname. Aplikacioni lexon ngalast_name. Baza e të dhënave ndodhet në versioninv2, duke përfshirë kolonat silast_name, ashtu edhesurname. surnameështë një kopje e last_name. (VËREJTJE: kjo kolonë nuk duhet të ketë kufizimin not null) - shpërndarjen e aplikacionit në versionin
3.0.0, që ruan të dhëna vetëm nësurnamedhe lexon nga surname. Sa i përket Bazës së të Dhënave, bëhet migrimi i funditlast_namenësurname. Po ashtu, kufizimi NOT NULL shkëlqet ngalast_name. Baza e të dhënave tani është në versioninv3 - shpërndarjen e aplikacionit në versionin
4.0.0— nuk bëhen ndryshime në kod. Depoimi i bazës së të dhënavev4, e cila fshinlast_name. Këtu mund të shtoni çdo kufizim të humbur në Bazën e të Dhënave.
Duke ndjekur këtë qasje, mund të riktheheni gjithmonë një version më parë, pa prishur kompatibilitetin e Bazës së të Dhënave / aplikacionit.
Kodi
I gjithë kodi i përdorur në këtë artikull është në dispozicion në . Më poshtë përshkrimi shtesë.
Projekte
Pas klonimit të depoes, do të shihni strukturën e mëposhtme të dosjeve.
├── boot-flyway-v1 - versioni 1.0.0 i aplikacionit me v1 të skemës
├── boot-flyway-v2 - versioni 2.0.0 i aplikacionit me v2 të skemës (kompatibil prapa - aplikacioni mund të rikthehet)
├── boot-flyway-v2-bad - versioni 2.0.0.BAD i aplikacionit me v2bad të skemës (inkompatibil prapa - aplikacioni nuk mund të rikthehet)
├── boot-flyway-v3 - versioni 3.0.0 i aplikacionit me v3 të skemës (aplikacioni mund të rikthehet)
└── boot-flyway-v4 - versioni 4.0.0 i aplikacionit me v4 të skemës (aplikacioni mund të rikthehet)Skripte
Mund të ekzekutoni skenarët e përshkruar në skriptet më poshtë, të cilët demonstrojnë ndryshimet e përputhshme dhe të papërputhshme në Bazën e të Dhënave.
Për të parë rastin me ndryshimet e përputhshme, ekzekutoni:
.\/scripts\/scenario_backward_compatible.shDhe për të parë rastin me ndryshimet e papërputhshme, ekzekutoni:
.\/scripts\/scenario_backward_incompatible.shShembulli i Spring Boot Flyway
Të gjithë shembujt janë marrë nga Shembulli i Spring Boot Flyway.
Mund të shikoni në http://localhost:8080/flyway, aty është lista e skripteve.
Ky shembull gjithashtu përfshin konsolën H2 (në adresën http://localhost:8080/h2-console), në mënyrë që të mund të shqyrtoni gjendjen e Bazës së të Dhënave (URL jdbc në mënyrë të paracaktuar — jdbc:h2:mem:testdb).
Shtesë
Lexoni gjithashtu artikuj të tjerë në blogun tonë:
Burimi: habr.com
