
Ky artikull shpjegon në detaje se si të zgjidhen çështjet e përputhshmërisë së bazës së të dhënave në vendosje. Ne do t'ju tregojmë se çfarë mund të ndodhë me aplikacionet tuaja të prodhimit nëse përpiqeni të vendosni pa përgatitje paraprake. Më pas do të kalojmë nëpër fazat e ciklit jetësor të aplikacionit që kërkohet të ketë zero kohë joproduktive (përafërsisht. korsi: më tej - zero joproduktive). Rezultati i operacioneve tona do të jetë aplikimi i ndryshimit të bazës së të dhënave të papajtueshme me prapavijën në një mënyrë të përputhshme me prapavijën.
Nëse dëshironi të kuptoni shembujt e kodit nga artikulli, mund t'i gjeni në .
Paraqitje
Zbarkim zero joproduktive
ĂfarĂ« mistike vendosje zero joproduktive? Ju mund tĂ« thoni se kjo Ă«shtĂ« kur aplikacioni juaj vendoset nĂ« atĂ« mĂ«nyrĂ« qĂ« ju mund tĂ« prezantoni me sukses njĂ« version tĂ« ri tĂ« aplikacionit nĂ« prodhim, ndĂ«rsa pĂ«rdoruesi nuk e vĂ«ren mosdisponueshmĂ«rinĂ« e tij. Nga perspektiva e pĂ«rdoruesit dhe e kompanisĂ«, ky Ă«shtĂ« skenari mĂ« i mirĂ« i mundshĂ«m i vendosjes sepse lejon futjen e veçorive tĂ« reja dhe rregullimin e gabimeve pa ndĂ«rprerje.
Si të arrihet kjo? Ka disa mënyra, këtu është një prej tyre:
- vendos versionin nr. 1 të shërbimit tuaj
- kryeni një migrim të bazës së të dhënave
- Vendosni versionin #2 të shërbimit tuaj paralelisht me versionin #1
- Sapo të shihni se versioni nr. 2 funksionon siç duhet, hiqni versionin nr. 1
- gati!
Lehtë, apo jo? Fatkeqësisht, nuk është aq e thjeshtë dhe do ta shikojmë në detaje më vonë. Tani le të kontrollojmë një proces tjetër mjaft të zakonshëm të vendosjes - vendosjen e gjelbër blu.
A keni dëgjuar ndonjëherë për ? Cloud Foundry e bën këtë jashtëzakonisht të lehtë. Vetëm shikoni , ku e përshkruajmë këtë në mënyrë më të detajuar. Për ta përmbledhur shkurtimisht, le t'ju kujtojmë se si të bëni vendosjen e gjelbër blu:
- sigurohuni qĂ« tĂ« funksionojnĂ« dy kopje tĂ« kodit tuaj tĂ« prodhimit (âbluâ dhe âjeshileâ);
- drejtoje të gjithë trafikun në mjedisin blu, d.m.th. në mënyrë që URL-të e prodhimit të tregojnë atje;
- vendos dhe teston të gjitha ndryshimet e aplikacionit në një mjedis të gjelbër;
- ndërroni url-të nga mjedisi blu në jeshil
Vendosja e gjelbër blu është një qasje që ju lejon të prezantoni lehtësisht veçori të reja pa u shqetësuar për prishjen e prodhimit. Kjo për faktin se edhe nëse ndodh diçka, ju mund të ktheheni lehtësisht në mjedisin e mëparshëm thjesht "duke goditur një çelës".
Pasi tĂ« keni lexuar tĂ« gjitha sa mĂ« sipĂ«r, mund tĂ« bĂ«ni pyetjen: ĂfarĂ« lidhje ka zero joproduktive me vendosjen e gjelbĂ«r blu?
Epo, ato kanë mjaft të përbashkëta, pasi mbajtja e dy kopjeve të të njëjtit mjedis kërkon përpjekje të dyfishtë për t'i ruajtur ato. Kjo është arsyeja pse disa ekipe pretendojnë , ndiqni një variacion të kësaj qasjeje:
Një tjetër mundësi është të përdorni të njëjtën bazë të dhënash, duke krijuar çelësa blu-jeshile për shtresat e ueb-it dhe të domenit. Në këtë qasje, baza e të dhënave shpesh mund të jetë problem, veçanërisht kur duhet të ndryshoni skemën e saj për të mbështetur një version të ri të softuerit.
Dhe këtu kemi ardhur te problemi kryesor në këtë artikull. bazës së të dhënave. Le t'i hedhim një vështrim tjetër kësaj fraze.
kryeni një migrim të bazës së të dhënave.
Tani duhet t'i bëni vetes pyetjen - çka nëse ndryshimi i bazës së të dhënave nuk është i përputhshëm me të prapme? A nuk do të prishet versioni im i parë i aplikacionit? Në fakt, kjo është pikërisht ajo që do të ndodhë...
Pra, edhe përkundër përfitimeve të mëdha të kohës së ndërprerjes zero / vendosjes së gjelbër blu, kompanitë priren të ndjekin procesin e mëposhtëm më të sigurt për vendosjen e aplikacioneve të tyre:
- përgatitni një paketë me një version të ri të aplikacionit
- mbyllni një aplikacion që funksionon
- ekzekutoni skriptet për të migruar bazën e të dhënave
- vendos dhe lëshon një version të ri të aplikacionit
Në këtë artikull, ne do të detajojmë se si mund të punoni me bazën e të dhënave dhe kodin tuaj për të përfituar nga vendosja zero joproduktive.
Problemet e bazës së të dhënave
Nëse keni një aplikacion pa shtetësi që nuk ruan asnjë të dhënë në bazën e të dhënave, mund të merrni zero vendosje joproduktive menjëherë. Fatkeqësisht, shumica e programeve kompjuterike duhet të ruajnë të dhënat diku. Kjo është arsyeja pse duhet të mendoni dy herë përpara se të bëni ndonjë ndryshim në qark. Përpara se të futemi në detajet se si të ndryshojmë skemën në mënyrë që vendosja pa ndërprerje të jetë e mundur, le të përqendrohemi së pari në skemën e versionimit.
Skema e versionimit
Në këtë artikull do të përdorim si një mjet kontrolli versioni (përafërsisht. Përkthimi: ne po flasim për migrimet e bazës së të dhënave). Natyrisht, ne do të shkruajmë gjithashtu një aplikacion Spring Boot që ka mbështetje të integruar Flyway dhe do të kryejë migrimin e skemës gjatë konfigurimit të kontekstit të aplikacionit. Kur përdorni Flyway, mund të ruani skriptet e migrimit në dosjen e projekteve tuaja (si parazgjedhje në classpath:db/migration). Këtu mund të shihni një shembull të skedarëve të tillë migrimi
âââ db
âââ migration
âââ V1__init.sql
âââ V2__Add_surname.sql
âââ V3__Final_migration.sql
âââ V4__Remove_lastname.sqlNĂ« kĂ«tĂ« shembull shohim 4 skripta migrimi qĂ«, nĂ«se nuk ekzekutohen mĂ« parĂ«, do tĂ« ekzekutohen njĂ«ri pas tjetrit kur tĂ« fillojĂ« aplikacioni. Le tĂ« shohim njĂ« nga skedarĂ«t (V1__init.sql) si nje 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');Gjithçka është krejtësisht e vetëshpjegueshme: ju mund të përdorni SQL për të përcaktuar se si duhet modifikuar databaza juaj. Për më shumë informacion rreth Spring Boot dhe Flyway, shikoni .
Duke përdorur një mjet kontrolli burimi me Spring Boot, ju merrni 2 përfitime të mëdha:
- ju ndani ndryshimet e bazës së të dhënave nga ndryshimet e kodit
- Migrimi i bazës së të dhënave ndodh së bashku me paraqitjen e aplikacionit tuaj, d.m.th. procesi juaj i vendosjes është thjeshtuar
Zgjidhja e problemeve të bazës së të dhënave
Në pjesën tjetër të artikullit, ne do të përqendrohemi në shikimin e dy qasjeve për ndryshimet e bazës së të dhënave.
- papajtueshmëria e prapambetur
- përputhshmëria e prapambetur
E para do të konsiderohet si një paralajmërim se nuk duhet të kryeni vendosjen e kohës së ndërprerjes zero pa përgatitje paraprake... E dyta ofron një zgjidhje se si mund të kryeni një vendosje pa ndërprerje dhe në të njëjtën kohë të ruani përputhshmërinë e prapambetur.
Projekti ynĂ« pĂ«r tĂ« cilin do tĂ« punojmĂ« do tĂ« jetĂ« njĂ« aplikacion i thjeshtĂ« Spring Boot Flyway qĂ« ka Person Ń first_name Đž last_name nĂ« bazĂ«n e tĂ« dhĂ«nave (pĂ«rafĂ«rsisht. pĂ«rkthimi: Person Ă«shtĂ« njĂ« tabelĂ« dhe first_name Đž last_name - kĂ«to janĂ« fushat nĂ« tĂ«). Ne duam tĂ« riemĂ«rtojmĂ« last_name ĐČ surname.
Supozimet
Përpara se të futemi në detaje, ka disa supozime që duhet të bëjmë në lidhje me aplikacionet tona. Rezultati kryesor që duam të arrijmë do të jetë një proces mjaft i thjeshtë.
ShĂ«nimi. Biznes PRO-KĂSHILLA. Thjeshtimi i proceseve mund t'ju kursejĂ« shumĂ« para nĂ« mbĂ«shtetje (sa mĂ« shumĂ« njerĂ«z tĂ« keni qĂ« punojnĂ« pĂ«r kompaninĂ« tuaj, aq mĂ« shumĂ« para mund tĂ« kurseni)!
Nuk ka nevojë për të rikthyer bazën e të dhënave
Kjo thjeshton procesin e vendosjes (disa rikthime të bazës së të dhënave janë pothuajse të pamundura, siç është rikthimi i fshirjes). Ne preferojmë të rikthejmë vetëm aplikacionet. Në këtë mënyrë, edhe nëse keni baza të të dhënave të ndryshme (për shembull, SQL dhe NoSQL), tubacioni juaj i vendosjes do të duket i njëjtë.
Duhet të jetë GJITHMONà e mundur që aplikacioni të kthehet një version prapa (jo më shumë)
Rikthimi duhet të bëhet vetëm kur është e nevojshme. Nëse ka një gabim në versionin aktual që nuk rregullohet lehtë, duhet të jemi në gjendje të kthehemi në versionin më të fundit të punës. Supozojmë se ky version i fundit i punës është ai i mëparshmi. Ruajtja e përputhshmërisë së kodit dhe bazës së të dhënave për më shumë se një paraqitje do të ishte jashtëzakonisht e vështirë dhe e shtrenjtë.
Shënimi. Për lexueshmëri më të madhe, në këtë artikull 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 bazës së të dhënave
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 personit 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
+ "]";
}
}Riemërtimi i kolonës i papajtueshëm prapa
Le të shohim një shembull se si të ndryshojmë emrin e një kolone:
Vëmendje. Shembulli i mëposhtëm do t'i prishë gjërat qëllimisht. Ne e tregojmë këtë për të demonstruar problemin e përputhshmërisë së 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 instanca (të vjetra dhe të reja) në të njëjtën kohë. Kështu, vendosja e kohës së ndërprerjes zero do të jetë e vështirë të arrihet (nëse merren parasysh supozimet, në fakt është e pamundur).
Testimi A/B
Situata aktuale është se ne kemi një version aplikacioni 1.0.0, të vendosura në prodhim dhe në bazën e të dhënave v1. Duhet të vendosim një shembull të dytë të aplikacionit, version 2.0.0.BAD, dhe përditësoni bazën e të dhënave në v2bad.
hapa:
- vendoset një shembull i ri i aplikacionit të versionit
2.0.0.BADi cili përditëson bazën e të dhënave nëv2bad - në bazën e të dhënave
v2badkolonëlast_namenuk ekziston më - u ndryshua nësurname - Përditësimi i bazës së të dhënave dhe aplikacionit ishte i suksesshëm dhe disa raste janë duke u ekzekutuar
1.0.0, të tjerët - në2.0.0.BAD. Gjithçka është e lidhur me bazën e të dhënavev2bad - të gjitha rastet e versionit
1.0.0do të fillojnë të hedhin gabime sepse do të përpiqen të fusin të dhëna në kolonëlast_nameqë nuk ekziston më - të gjitha rastet e versionit
2.0.0.BADdo të funksionojë pa probleme
Siç mund ta shihni, nëse bëjmë ndryshime të papajtueshme prapa në bazën e të dhënave dhe aplikacionit, testimi A/B është i pamundur.
Rikthimi i aplikacionit
Le të supozojmë se pasi të përpiqemi të bëjmë vendosjen e A/B (përafërsisht. per.: autori ndoshta ka menduar këtu testimin A/B) vendosëm që duhet ta kthejmë aplikacionin në version 1.0.0. Le të themi se nuk duam të rikthejmë bazën e të dhënave.
hapa:
- ne ndalojmë shembullin e aplikacionit të versionit
2.0.0.BAD - baza e të dhënave është ende
v2bad - që nga versioni
1.0.0nuk e kupton se çfarë ështësurname, do të shohim gabime - ferri ka dalë, nuk mund të kthehemi më
Siç mund ta shihni, nëse bëjmë ndryshime të papajtueshme në bazën e të dhënave dhe aplikacionit, nuk mund të kthehemi në versionin e mëparshëm.
Regjistrat e ekzekutimit të skriptit
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"}Ndryshimet e bazës së të dhënave
Skripti i migrimit qĂ« riemĂ«ron last_name ĐČ surname
Burimi i skenarit 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 që riemëron last_name.
-- This change is backward incompatible - you can't do A/B testing
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;Ndryshimet e kodit
Ne kemi ndryshuar emrin e fushës lastName mbi surname.
Riemërtimi i një kolone në një mënyrë të përputhshme me prapavijën
Kjo është situata më e zakonshme që mund të hasim. Ne duhet të bëjmë ndryshime të papajtueshme prapa. Ne kemi vërtetuar tashmë se për vendosjen me kohë jo të ndërprerjes, nuk duhet të aplikojmë thjesht migrimin e bazës së të dhënave pa hapa shtesë. Në këtë pjesë të artikullit, ne do të kryejmë 3 vendosje të aplikacionit së bashku me migrimet e bazës së të dhënave për të arritur rezultatin e dëshiruar duke ruajtur përputhshmërinë e prapambetur.
Shënimi. Kujtojmë që ne kemi një bazë të dhënash versionesh
v1. Ai përmban kolonafirst_nameОlast_name. Ne duhet të ndryshojmëlast_namembisurname. Kemi edhe versionin e aplikacionit1.0.0,e cila ende nuk është përdorursurname.
Hapi 2: Shtoni mbiemrin
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ë pajtueshme në bazën e të dhënave. Në të njëjtën kohë, nëse e rikthejmë JAR-in ose kemi një JAR të vjetër që funksionon, ai nuk do të prishet gjatë ekzekutimit.
Ne po nxjerrim një version të ri
hapa:
- kryeni një migrim të bazës së të dhënave për të krijuar një kolonë të re
surname. Tani versioni juaj DBv2 - kopjoni të dhënat nga
last_nameĐČsurname. ĐбŃаŃĐžŃĐ” ĐČĐœĐžĐŒĐ°ĐœĐžĐ”qĂ« nĂ«se keni shumĂ« nga kĂ«to tĂ« dhĂ«na, duhet tĂ« merrni parasysh migrimin e grupeve! - shkruani kodin ku janĂ« pĂ«rdorur TĂ DYJA Đž i riDhe ŃŃаŃŃĐč kolonĂ«. Tani versioni i aplikacionit tuaj
2.0.0 - lexoni vlerën nga kolona
surname, nëse nuk ështënull, ose nga last_name, nësesurnamee paspecifikuar. Ju mund të fshinigetLastName()nga kodi, pasi ai do të dalënullkur ktheni aplikacionin tuaj nga3.0.0tek2.0.0.
Nëse jeni duke përdorur Spring Boot Flyway, këto dy hapa do të kryhen gjatë fillimit të versionit 2.0.0 aplikacionet. Nëse e përdorni manualisht mjetin e versionimit të bazës së të dhënave, do t'ju duhet të bëni dy gjëra të ndryshme për ta bërë këtë (së pari përditësoni versionin db manualisht dhe më pas vendosni aplikacionin e ri).
E rëndësishme Mos harroni se kolona e krijuar rishtazi NUK DUHET të jetë JO NULL. Nëse bëni një rikthim, aplikacioni i vjetër nuk di për kolonën e re dhe nuk do ta instalojë atë gjatë
Insert.Por nëse shtoni këtë kufizim dhe db juaj do të jetëv2, kjo do të kërkojë vendosjen e vlerës së kolonës së re. Që do të çojë në shkelje të kufizimeve.E rëndësishme Ju duhet të hiqni metodën
getLastName(), sepse në version3.0.0Nuk ka asnjë koncept të një kolone në kodlast_name. Kjo do të thotë se null do të vendoset atje. Mund të lini metodën dhe të shtoni kontrolle përnull, por një zgjidhje shumë më e mirë do të ishte të sigurohesh që në logjikëgetSurname()keni zgjedhur vlerën e saktë jo zero.
Testimi A/B
Situata aktuale është se ne kemi një version aplikacioni 1.0.0, i vendosur në prodhim dhe baza e të dhënave në v1. Duhet të vendosim një shembull të dytë të aplikacionit të versionit 2.0.0e cila do të përditësojë bazën e të dhënave në v2.
hapa:
- vendoset një shembull i ri i aplikacionit të versionit
2.0.0i cili përditëson bazën e të dhënave nëv2 - ndërkohë disa kërkesa u përpunuan nga instancat e versionit
1.0.0 - përditësimi ishte i suksesshëm dhe ju keni disa raste të ekzekutimit të aplikacionit të versionit
1.0.0dhe versione të tjera2.0.0.Të gjithë komunikojnë me bazën e të dhënave nëv2 - version
1.0.0nuk përdor kolonën e mbiemrit në bazën e të dhënave, por versionin2.0.0përdor. Ata nuk ndërhyjnë me njëri-tjetrin dhe nuk duhet të ketë gabime. - version
2.0.0ruan të dhënat si në kolonën e vjetër ashtu edhe në atë të re, duke siguruar përputhshmëri të prapambetur
E rëndësishme Nëse keni ndonjë pyetje që numëron artikujt bazuar në vlerat nga kolona e vjetër/e re, duhet të mbani mend se tani keni vlera të kopjuara (ka shumë të ngjarë që ato janë ende duke migruar). Për shembull, nëse dëshironi të numëroni numrin e përdoruesve, mbiemri i të cilëve (sido që të quhet kolona) fillon me shkronjën
A, pastaj derisa tĂ« pĂ«rfundojĂ« migrimi i tĂ« dhĂ«nave (oldânewkolonĂ«) mund tĂ« keni tĂ« dhĂ«na jokonsistente nĂ«se kĂ«rkoni njĂ« kolonĂ« tĂ« re.
Rikthimi i aplikacionit
Tani kemi versionin e aplikacionit 2.0.0 dhe baza e të dhënave në v2.
hapa:
- kthejeni aplikacionin tuaj në version
1.0.0. - version
1.0.0nuk përdor një kolonë në bazën e të dhënavesurname, kështu që rikthimi duhet të jetë i suksesshëm
DB ndryshon
Baza e të dhënave përmban një kolonë me emrin last_name.
Skripti 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');Shto skript surname.
Vëmendje. Mos harroni se ju NUK MUND Tà SHTONI asnjë kufizim NOT NULL në kolonën që po shtoni. Nëse e ktheni prapa JAR-in, versioni i vjetër nuk do të ketë asnjë ide për kolonën e shtuar dhe do ta vendosë automatikisht në NULL. Nëse ekziston një kufizim i tillë, aplikacioni i vjetër thjesht do të prishet.
-- 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_nameNdryshimet e kodit
Ne ruajmë të dhënat si last_name, dhe në surname. Në të njëjtën kohë lexojmë nga last_name, pasi kjo kolonë është më e rëndësishme. Gjatë procesit të vendosjes, disa kërkesa mund të jenë përpunuar nga një shembull 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 mbiemrit nga kodi
Versioni i aplikacionit: 3.0.0
Versioni i DB:v3
Koment
shënim per.: Me sa duket, në artikullin origjinal autori gabimisht kopjoi tekstin e këtij blloku nga hapi 2. Në këtë hap, duhet të bëhen ndryshime në kodin e aplikacionit që synojnë heqjen e funksionalitetit që përdor kolonën last_name.
Duke shtuar një kolonë të re dhe duke kopjuar përmbajtjen e saj, ne krijuam ndryshime të pajtueshme në bazën e të dhënave. Gjithashtu, nëse e kthejmë JAR-in ose kemi një JAR të vjetër që funksionon, ai nuk do të prishet gjatë ekzekutimit.
Rikthimi i aplikacionit
Aktualisht kemi versionin e aplikacionit 3.0.0 dhe bazës së të dhënave v3. Version 3.0.0 nuk ruan të dhënat në last_name. Kjo do të thotë se në surname ruhet informacioni më i përditësuar.
hapa:
- kthejeni aplikacionin tuaj në version
2.0.0. - version
2.0.0përdor dhelast_nameОsurname. - version
2.0.0do të marrësurname, nëse nuk është zero, përndryshe -last_name
Ndryshimet e bazës së të dhënave
Nuk ka ndryshime strukturore në bazën e të dhënave. Skripti i mëposhtëm ekzekutohet për të kryer migrimin përfundimtar të të dhënave të vjetra:
-- 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;Ndryshimet e kodit
shënim per.: Përshkrimi i këtij blloku gjithashtu u kopjua gabimisht nga autori nga hapi 2. Në përputhje me logjikën e artikullit, ndryshimet në kod në këtë hap duhet të synojnë heqjen prej tij të elementeve që punojnë me kolonën last_name.
Ne ruajmë të dhënat si last_name, dhe në surname. Për më tepër, lexojmë nga kolona last_name, pasi është më e rëndësishmja. Gjatë procesit të vendosjes, disa kërkesa mund të përpunohen nga një shembull që nuk është përmirë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 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: Heqja e mbiemrit nga baza e të dhënave
Versioni i aplikacionit: 4.0.0
Versioni i DB: v4
Koment
Për faktin se kodi i versionit 3.0.0 nuk e përdori kolonën last_name, asgjë e keqe nuk do të ndodhë gjatë ekzekutimit nëse kthehemi përsëri në 3.0.0 pas heqjes së një kolone nga baza e të dhënave.
Regjistrat e ekzekutimit të skriptit
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 ndryshon
për v3 thjesht heqim kolonën last_name dhe shtoni kufizime që mungojnë.
-- 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;Ndryshimet e kodit
Nuk ka ndryshime në kod.
Prodhim
Zbatuam me sukses një ndryshim të emrit të kolonës të papajtueshëm me prapavijë duke kryer disa vendosje të pajtueshme me prapavijën. Më poshtë është një përmbledhje e veprimeve të kryera:
- vendosja e versionit të aplikacionit
1.0.0Ńv1skema e bazĂ«s sĂ« tĂ« dhĂ«nave (emri i kolonĂ«s =last_name) - vendosja e versionit tĂ« aplikacionit
2.0.0,i cili ruan tĂ« dhĂ«nat nĂ«last_nameĐžsurname. Aplikacioni lexon ngalast_name. Baza e tĂ« dhĂ«nave Ă«shtĂ« nĂ« versionv2qĂ« pĂ«rmban kolona silast_nameDhesurname. surnameĂ«shtĂ« njĂ« kopje e last_name. (SHĂNIM: Kjo kolonĂ« nuk duhet tĂ« ketĂ« njĂ« kufizim jo null) - vendosja e versionit tĂ« aplikacionit
3.0.0, i cili ruan vetĂ«m tĂ« dhĂ«nat nĂ«surnamedhe lexon nga mbiemri. Sa i pĂ«rket bazĂ«s sĂ« tĂ« dhĂ«nave, migrimi i fundit po ndodhlast_nameĐČsurname. Gjithashtu njĂ« kufizim JO NULL hequr ngalast_name. Baza e tĂ« dhĂ«nave Ă«shtĂ« tani nĂ« versionv3 - vendosja e versionit tĂ« aplikacionit
4.0.0- nuk janë bërë ndryshime në kod. Vendosja e bazës së të dhënavev4, e cila heqlast_name. Këtu mund të shtoni çdo kufizim që mungon në bazën e të dhënave.
Duke ndjekur këtë qasje, gjithmonë mund të rikthehet një version pa prishur pajtueshmërinë e bazës së të dhënave/aplikacionit.
Kod
I gjithë kodi i përdorur në këtë artikull është i disponueshëm në . Më poshtë është një përshkrim shtesë.
projektet
Pas klonimit të depove, do të shihni strukturën e mëposhtme të dosjeve.
âââ 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)Skenare
Ju mund të ekzekutoni skriptet e përshkruara në skriptet më poshtë, të cilat do të demonstrojnë ndryshime të përputhshme dhe të papajtueshme në bazën e të dhënave.
Të shikosh rasti me ndryshime të përputhshme prapa, vraponi:
./scripts/scenario_backward_compatible.shDhe për të parë rast me ndryshime të papajtueshme prapa, vraponi:
./scripts/scenario_backward_incompatible.shShembull i çizmeve pranverore Flyway
Të gjithë shembujt janë marrë nga Spring Boot Sample Flyway.
Ju mund t'i hidhni një sy http://localhost:8080/flyway, ekziston një listë skriptesh.
Ky shembull përfshin gjithashtu konsolën H2 (në http://localhost:8080/h2-console) kështu që ju mund të shikoni statusin e bazës së të dhënave (URL e parazgjedhur jdbc është jdbc:h2:mem:testdb).
Përveç kësaj
Lexoni gjithashtu artikuj të tjerë në blogun tonë:
Burimi: www.habr.com
