
I denne artikkelen forklarer vi i detalj hvordan man løser problemer med databasekompatibilitet ved distribusjon. Vi vil fortelle hva som kan skje med applikasjonene dine i produksjonen hvis du prøver å distribuere uten forberedelse. Deretter vil vi gå gjennom livssyklusfasene for applikasjonen som er nødvendige for å ha null nedetid (merk. overs.: videre — null nedetid). Resultatet av våre operasjoner vil være å bruke en bakoverkompatibel måte å implementere en inkompatibel endring av databasen.
Hvis du vil se eksempler på kode fra artikkelen, finner du dem på .
Innledning
Null nedetid distribusjon
Hva er denne mystiske null nedetid distribusjon? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.
Hvordan oppnå dette? Det er flere måter, her er en av dem:
- distribuer versjon nr. 1 av tjenesten din
- utfør databasemigrering
- distribuer versjon nr. 2 av tjenesten din parallelt med versjon nr. 1
- så snart du ser at versjon nr. 2 fungerer som den skal, fjerner du versjon nr. 1
- ferdig!
Enkelt, ikke sant? Dessverre er det ikke så enkelt, og vi vil se nærmere på det senere. Nå skal vi sjekke en annen ganske vanlig distribusjonsprosess — blågrønn distribusjon.
Har du noen gang hørt om ? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на , hvor vi beskriver dette mer detaljert. Kort oppsummert minner vi om hvordan man utfører blågrønn distribusjon:
- ha to kopier av produksjonskoden din i drift ("blå" og "grønn");
- lede all trafikk til den blå miljøet, dvs. så produksjons-URLene peker dit;
- distribuere og teste alle endringer i applikasjonen i den grønne miljøet;
- bytte produksjons-URLene fra blå til grønn miljø
Blågrønn distribusjon er en tilnærming som lar deg enkelt legge til nye funksjoner uten å bekymre deg for at produksjonen skal krasje. Dette skyldes at selv om noe skjer, kan du raskt gå tilbake til den tidligere miljøet ved å bare "vri på bryteren".
Etter å ha lest alt dette kan du stille spørsmålet: Hva har null nedetid med blågrønn distribusjon å gjøre?
Vel, de har ganske mye til felles, ettersom støtte for to kopier av det samme miljøet krever dobbel innsats for vedlikehold. Derfor holder noen team, ifølge , seg til en variasjon av denne tilnærmingen:
En annen tilnærming er å bruke den samme databasen ved å opprette blå-grønne veksler for web- og domenelag. I en slik tilnærming kan databasene ofte bli et problem, spesielt når du må endre skjemaet for å støtte en ny versjon av programvaren.
Og her nærmer vi oss det viktigste problemet i denne artikkelen. Database. La oss ta et nytt blikk på denne setningen.
Utfør databasemigreringen.
Nå bør du stille deg selv spørsmålet – hva om databasemodifikasjonen ikke er bakoverkompatibel? Vil ikke den første versjonen av applikasjonen min bryte? Faktisk, det vil den gjøre…
Dermed, selv med de enorme fordelene med null nedetid / blå-grønn distribusjon, har selskaper en tendens til å følge den neste sikrere prosessen for distribusjon av sine applikasjoner:
- forbered en pakke med den nye versjonen av applikasjonen
- deaktiver den kjørende applikasjonen
- kjør skriptene for databasemigrering
- distribuer og start den nye versjonen av applikasjonen
I denne artikkelen skal vi detaljert beskrive hvordan du kan arbeide med databasen og koden for å dra nytte av fordelene med null nedetid distribusjon.
Databaseløsninger
Hvis du har en stateless applikasjon som ikke lagrer noen data i databasen, kan du oppnå null nedetid distribusjon med en gang. Dessverre må de fleste programvarelagre data et sted. Derfor må du tenke deg om to ganger før du gjør endringer i skjemaet. Før vi går inn i detaljene om hvordan man kan endre skjemaet på en måte som muliggjør distribusjon uten nedetid, la oss først fokusere på versjonskontroll.
Versjonskontroll
I denne artikkelen vil vi bruke som verktøy for versjonskontroll (merkn. overs.: Dette refererer til databasemigreringer). Naturligvis vil vi også skrive en Spring Boot-applikasjon som har innebygd støtte for Flyway og som vil utføre skjema-migrering under oppstart av applikasjonskonteksten. Når du bruker Flyway, kan du lagre migreringsskriptene i prosjektenes mappe (som standard i classpath:db/migration). Her kan du se et eksempel på slike migreringsfiler
└── db
└── migration
├── V1__init.sql
├── V2__Add_surname.sql
├── V3__Final_migration.sql
└── V4__Remove_lastname.sqlI dette eksemplet ser vi 4 migreringsscenarier som, hvis de ikke har blitt utført tidligere, vil kjøre etter hverandre når applikasjonen startes. La oss se på en av filene (V1__init.sql) som et eksempel.
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');Alt taler for seg selv: Du kan bruke SQL til å definere hvordan databasen din skal endres. For mer informasjon om Spring Boot og Flyway, se .
Ved å bruke et versjonskontrollverktøy med Spring Boot får du 2 store fordeler:
- du skiller endringer i databasen fra endringer i koden
- databasemigrasjonen skjer samtidig med utrullingen av applikasjonen, dvs. prosessen din for distribusjon forenkles
Løse databaseproblemer
I neste del av artikkelen vil vi fokusere på å se på to tilnærminger til endringer i databasen.
- bakoverkompatibilitet
- fremoverkompatibilitet
Den første vil bli vurdert som en advarsel om at du ikke bør utføre null nedetid distribusjon uten forberedelser ... Den andre tilbyr en løsning på hvordan man kan implementere distribusjoner uten nedetid og samtidig opprettholde bakoverkompatibiliteten.
Prosjektet vi skal jobbe med, vil være en enkel Spring Boot Flyway-applikasjon med en Person med first_name og last_name i databasen (merkn. overs.: Person er en tabell, og first_name og last_name er feltene i den). Vi ønsker å endre navnet på last_name i surname.
Forutsetninger
Før vi dykker dypere inn i detaljene, må vi markere et par forutsetninger angående applikasjonene våre. Hovedresultatet vi ønsker å oppnå, vil være en ganske enkel prosess.
Notat. Business PRO-TIP. Å forenkle prosesser kan spare deg for mye penger i vedlikehold (jo flere mennesker som jobber i selskapet ditt, jo mer penger kan du spare)!
Ikke gjør tilbakerulling av databasen
Dette forenkler distribusjonsprosessen (noen tilbakerullinger av databaser er i praksis umulige, som tilbakerulling av slettede data). Vi foretrekker å bare rulle tilbake applikasjoner. Dermed, selv om du har forskjellige databaser (for eksempel SQL og NoSQL), vil distribusjonslinjen din se lik ut.
Det må alltid være mulig å rulle tilbake applikasjonen én versjon tilbake (ikke mer)
Rullen kaste skal berre utførast når det er nødvendig. Dersom det er ein feil i den noverande versjonen som er vanskeleg å rette, må vi ha moglegheit til å gå tilbake til siste fungerande versjon. Vi antar at denne siste fungerande versjonen er den tidlegare. Å oppretthalde kode- og databasen kompatibilitet for meir enn ein oppdatering ville vere ekstremt vanskeleg og kostbart.
Notat. For betre lesbarheit vil vi endre hovudversjonen av applikasjonen i denne artikkelen.
Trinn 1: Opprinnelig tilstand
Applikasjonsversjon: 1.0.0
DB-versjon: v1
Kommentar
Dette vil vere den opprinnelege tilstanden til applikasjonen.
DB-endringar
DB inneheld 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');Kode-endringar
Applikasjonen lagrar data Person 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
+ "]";
}
}Tilbakekompatibel omdøping av kolonne
La oss sjå på eit eksempel på korleis vi kan endre namn på kolonnen:
Merk. Det neste eksempelet vil bevisst føre til eit problem. Vi viser dette for å demonstrere problemet med databasen sin kompatibilitet.
Applikasjonsversjon: 2.0.0.BAD
DB-versjon: v2bad
Kommentar
De noverande endringane TILLATER oss ikkje å kjøre to instansar (gamal og ny) samtidig. Dermed vil zero downtime deployment vere vanskeleg å oppnå (gitt forutsetningane, er det faktisk umogeleg).
A/B-testing
Den noverande situasjonen er slik at vi har ein applikasjon av versjon 1.0.0, utplassert i produksjon, og DB v1. Vi må distribuere den andre instansen av applikasjonen, versjon 2.0.0.BAD, og oppdatere databasen til v2bad.
Trinn:
- den nye instansen av applikasjonen versjon
2.0.0.BAD, som oppdaterer databasen tilv2bad - i databasen
v2badkolonnelast_namefinnest ikkje lenger — den har blitt endra tilsurname - oppdatering av databasen og applikasjonen har gått bra, og nokre instansar kjører i
1.0.0, andre i2.0.0.BAD. Alle er knytt til DBv2bad - alle instansar av versjon
1.0.0vil begynne å gi feil, fordi dei vil prøve å sette inn data i kolonnenlast_name, som ikkje lenger finst - alle instansar av versjon
2.0.0.BADvil fungere utan problem
Som du ser, dersom vi gjer tilbakekompatible endringar i DB og applikasjonen, er A/B-testing umogeleg.
Rulle applikasjonen tilbake
La oss anta at etter å ha forsøkt å gjennomføre A/B deployment (Merk: forfattaren meinte sannsynlegvis A/B testing her) så bestemte vi oss for at vi må rulle applikasjonen tilbake til versjon 1.0.0. La oss anta at vi ikkje ønskjer å rulle databasen tilbake.
Trinn:
- vi stopper en applikasjonsinstans av versjon
2.0.0.BAD - databasen er fortsatt
v2bad - siden versjon
1.0.0ikke forstår hva som ersurname, vil vi se feil - helvete er sluppet løs, vi kan ikke gå tilbake lenger
Som du ser, hvis vi gjør bakoverkompatible endringer i DB og applikasjonen, kan vi ikke rulle tilbake til en tidligere versjon.
Logger for skripteksekvering
Bakoverkompatibel scenario:
01) Kjør 1.0.0
02) Vent på at appen (1.0.0) skal starte
03) Generer en person ved å kalle POST localhost:9991/person til versjon 1.0.0
04) Kjør 2.0.0.BAD
05) Vent på at appen (2.0.0.BAD) skal starte
06) Generer en person ved å kalle POST localhost:9991/person til versjon 1.0.0 < -- dette skal feile
07) Generer en person ved å kalle POST localhost:9992/person til versjon 2.0.0.BAD < -- dette skal passere
Starter appen i versjon 1.0.0
Generer en person i versjon 1.0.0
Sender en post til 127.0.0.1:9991/person. Dette er svaret:
{"firstName":"b73f639f-e176-4463-bf26-1135aace2f57","lastName":"b73f639f-e176-4463-bf26-1135aace2f57"}
Starter appen i versjon 2.0.0.BAD
Generer en person i versjon 1.0.0
Sender en post til 127.0.0.1:9991/person. Dette er svaret:
curl: (22) Den forespurte URL-en returnerte feilen: 500 Intern serverfeil
Generer en person i versjon 2.0.0.BAD
Sender en post til 127.0.0.1:9995/person. Dette er svaret:
{"firstName":"e156be2e-06b6-4730-9c43-6e14cfcda125","surname":"e156be2e-06b6-4730-9c43-6e14cfcda125"}DB-endringar
Migreringsskriptet som omdøper last_name i surname
Original 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');Skriptet som omdøper last_name.
-- Denne endringen er bakoverkompatibel - du kan ikke gjøre A/B-testing
ALTER TABLE PERSON ENDRE last_name surname VARCHAR;Kode-endringar
Vi har endret navnet på feltet lastName En funksjon har blitt surname.
Omdøping av kolonnen på en bakoverkompatibel måte
Dette er den vanligste situasjonen vi kan møte. Vi må gjøre bakoverkompatible endringer. Vi har allerede bevist at for distribusjon uten nedetid må vi ikke bare anvende databasemigreringen uten ytterligere tiltak. I denne delen av artikkelen vil vi utføre 3 distribusjoner av applikasjonen sammen med databasemigreringene for å oppnå det ønskede resultatet samtidig som vi opprettholder bakoverkompatibilitet.
Notat. Husk at vi har en DB versjon
v1. Den inneholder kolonnerfirst_nameoglast_name. Vi må endrelast_nameEn funksjon har blittsurname. Vi har også en applikasjon av versjon1.0.0,som ennå ikke brukersurname.
Trinn 2: Legger til surname
Applikasjonsversjon: 2.0.0
DB-versjon: v2
Kommentar
Ved å legge til en ny kolonne og kopiere dens innhold, lager vi bakoverkompatible endringer i databasen. På samme tid, hvis vi ruller tilbake JAR eller har en fungerende gammel JAR, vil den ikke bryte under kjøring.
Ruller ut ny versjon
Trinn:
- utfør databasemigrering for å opprette en ny kolonne
surname. Nå er din DB versjonv2 - kopier dataene fra
last_nameisurname. Legg merke til, som hvis du har mye av disse dataene, bør du vurdere batchmigrering! - Skriv kode der hvor BEGGE og seksjon, og gamle kolonne. Nå er applikasjonen din versjon
2.0.0 - les verdien fra kolonnen
surname, hvis den ikkenull, eller fra last_name, hvissurnameikke er angitt. Du kan fjernegetLastName()fra koden, da den vil returnerenullved tilbakestilling av applikasjonen din fra3.0.0til2.0.0.
Hvis du bruker Spring Boot Flyway, vil disse to trinnene bli utført under oppstart av versjonen 2.0.0 av applikasjonen. Hvis du kjører databaseversjonskontrollverktøyet manuelt, må du gjøre to ulike handlinger (først oppdater databasen manuelt, deretter distribuer det nye programmet).
Viktig. Husk at den nyopprettede kolonnen IKKE MÅ være NOT NULL. Hvis du gjør en tilbakestilling, vet ikke den gamle applikasjonen om den nye kolonnen og vil ikke sette den under
Insert.Men hvis du legger til dette kravet, og databasen din erv2, vil det kreve å sette en verdi for den nye kolonnen. Dette vil føre til brudd på begrensningene.Viktig. Du bør fjerne metoden
getLastName(), siden begrepet kolonne ikke finnes i versjonen3.0.0i koden. Dette betyr at det vil bli satt inn null. Du kan beholde metoden og legge til sjekker forlast_name, men en mye bedre løsning ville være å sørge for at i logikkennullgetSurname()valgte du riktig ikke-null verdi., distribuert på prod, og databasen i
A/B-testing
Den noverande situasjonen er slik at vi har ein applikasjon av versjon 1.0.0. Vi må distribuere en annen instans av applikasjonen versjon v1, som vil oppdatere databasen til 2.0.0mens noen forespørselene ble behandlet av instansene av versjonen v2.
Trinn:
- den nye instansen av applikasjonen versjon
2.0.0, som oppdaterer databasen tilv2 - oppdateringen ble vellykket, og du har flere fungerende instanser av applikasjonen versjon
1.0.0 - og de andre versjonene
1.0.0Alle kommuniserer med databasen i2.0.0.versjonv2 - bruker ikke i databasen kolonnen surname, mens versjonen
1.0.0bruker. De forstyrrer ikke hverandre, og det skal ikke være noen feil.2.0.0lagrer data både i den gamle og den nye kolonnen, noe som sikrer bakoverkompatibilitet - bruker ikke i databasen kolonnen surname, mens versjonen
2.0.0Hvis du har forespørselene som teller elementer basert på verdier fra den gamle / nye kolonnen, må du huske at nå har du duplisering av verdier (mest sannsynlig migrerer de fortsatt). For eksempel, hvis du ønsker å telle antall brukere hvis etternavn (uansett hva kolonnen heter) begynte med bokstaven
Viktig. , så til data-migreringen er ferdig (
Agammelkolonne) kan du ha inkonsistent data hvis du utfører en forespørsel til den nye kolonnen.→newNå har vi applikasjonen versjon
Rulle applikasjonen tilbake
og databasen i 2.0.0 tilbakestill applikasjonen din til versjon v2.
Trinn:
- bruker ikke i databasen kolonnen
1.0.0. - bruker ikke i databasen kolonnen surname, mens versjonen
1.0.0bruker ikke en kolonne i databasensurname, derfor må tilbakestillingen være vellykket
Endringer i DB
DB inneholder en kolonne med navnet last_name.
Opprinnelig 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 for å legge til surname.
Merk. Husk at DU IKKE KAN LEGGE TIL noen NOT NULL begrensninger i den nye kolonnen. Hvis du tilbakestiller JAR, vil den gamle versjonen ikke vite om den nye kolonnen, og automatisk sette verdien til NULL. I tilfelle det er en slik begrensning, vil den gamle applikasjonen straks feile.
-- MERK: Dette feltet kan ikke ha NOT NULL begrensningen, for hvis du tilbakestiller vil den gamle versjonen ikke vite om dette feltet
-- og vil alltid sette det til NULL
ALTER TABLE PERSON ADD surname varchar(255);
-- VI ANTAR AT DETTE ER EN RASK MIGRASJON - ELLERS MÅTTE VI MIGRERE I BATCHER
UPDATE PERSON SET PERSON.surname = PERSON.last_nameKode-endringar
Vi lagrer data både i last_name.ts surname. Vi leser fra last_name, siden denne kolonnen er mest aktuell. Under distribusjonsprosessen kan noen forespørseler ha blitt behandlet av en applikasjonsinstans som ikke er oppdatert ennå.
/*
* 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
+ "]";
}
}Trinn 3: Fjerne last_name fra koden
Applikasjonsversjon: 3.0.0
DB-versjon:v3
Kommentar
Obs. overs. : Det ser ut til at forfatteren av den opprinnelige artikkelen feilaktig kopierte teksten i denne blokken fra trinn 2. På dette trinnet skal endringer i applikasjonskoden gjøres for å fjerne funksjoner som bruker kolonnen last_name.
Ved å legge til en ny kolonne og kopiere innholdet, har vi skapt bakoverkompatible endringer i databasen. I tillegg, hvis vi tilbakestiller JAR eller har en fungerende gammel JAR, vil den ikke feile under kjøring.
Rulle applikasjonen tilbake
Vi har nå en applikasjon av versjon 3.0.0 og en database v3. Versjon 3.0.0 lagrer ikke data i last_name. Dette betyr at den mest aktuelle informasjonen er lagret i surname .
Trinn:
- bruker ikke i databasen kolonnen
2.0.0. - bruker ikke i databasen kolonnen surname, mens versjonen
2.0.0bruker oglast_nameogsurname. - bruker ikke i databasen kolonnen surname, mens versjonen
2.0.0tarsurname, hvis den ikke er null, ellers —last_name
DB-endringar
Det er ingen strukturelle endringer i databasen. Det kjøres følgende skript som utfører den endelige migrasjonen av gamle data:
-- VI ANTAR AT DETTE ER EN RASK MIGRASJON - ELLERS MÅTTE VI MIGRERE I BATCHER
-- VI SJEKKER OGSÅ IKKE OM VI OVERRIDER EKSISTERENDE ENHETER. VI MÅTTE SAMMENLIGNE
-- ENHETSVERDIER FOR Å SIKRE AT HVIS DET ALLEREDE ER EN ENHET MED ET HØYERE VERDI
-- VIL VI IKKE OVERRIDE DET.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;
-- FJERNER NOT NULL BEGRENSNINGEN; ELLERS VIL DU PRØVE Å SETTE INN NULL-VISNINGEN AV last_name
-- MED NOT_NULL-BEGRENSNING.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;Kode-endringar
Obs. overs. : Beskrivelsen av denne blokken ble også feilaktig kopiert av forfatteren fra trinn 2. I samsvar med artikkelens fortellerlogikk, skal endringer i koden på dette trinnet være rettet mot å fjerne elementer som jobber med kolonnen last_name.
Vi lagrer data både i last_name.ts surname. I tillegg leser vi fra kolonnen last_name, da den er mest relevant. Under distribusjonen kan noen forespørselene bli behandlet av en instans som fortsatt ikke er oppdatert.
/*
* 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
+ "]";
}
}Trinn 4: Fjerne last_name fra databasen
Applikasjonsversjon: 4.0.0
DB-versjon: v4
Kommentar
På grunn av at versjonskoden 3.0.0 ikke brukte kolonnen last_name, vil det ikke skje noe galt under kjøring hvis vi ruller tilbake til 3.0.0 etter fjerning av kolonnen fra databasen.
Logger for skripteksekvering
Vi vil gjøre det på følgende måte:
01) Kjør 1.0.0
02) Vent på at appen (1.0.0) starter opp
03) Generer en person ved å kalle POST localhost:9991/person til versjon 1.0.0
04) Kjør 2.0.0
05) Vent på at appen (2.0.0) starter opp
06) Generer en person ved å kalle POST localhost:9991/person til versjon 1.0.0
07) Generer en person ved å kalle POST localhost:9992/person til versjon 2.0.0
08) Stopp appen (1.0.0)
09) Kjør 3.0.0
10) Vent på at appen (3.0.0) starter opp
11) Generer en person ved å kalle POST localhost:9992/person til versjon 2.0.0
12) Generer en person ved å kalle POST localhost:9993/person til versjon 3.0.0
13) Stopp appen (3.0.0)
14) Kjør 4.0.0
15) Vent på at appen (4.0.0) starter opp
16) Generer en person ved å kalle POST localhost:9993/person til versjon 3.0.0
17) Generer en person ved å kalle POST localhost:9994/person til versjon 4.0.0
Starter appen i versjon 1.0.0
Generer en person i versjon 1.0.0
Sender et post til 127.0.0.1:9991/person. Dette er svaret:
{"firstName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2","lastName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2"}
Starter appen i versjon 2.0.0
Generer en person i versjon 1.0.0
Sender et post til 127.0.0.1:9991/person. Dette er svaret:
{"firstName":"e41ee756-4fa7-4737-b832-e28827a00deb","lastName":"e41ee756-4fa7-4737-b832-e28827a00deb"}
Generer en person i versjon 2.0.0
Sender et post til 127.0.0.1:9992/person. Dette er svaret:
{"firstName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","lastName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","surname":"0c1240f5-649a-4bc5-8aa9-cff855f3927f"}
Stopper appen 1.0.0
Starter appen i versjon 3.0.0
Generer en person i versjon 2.0.0
Sender et post til 127.0.0.1:9992/person. Dette er svaret:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}
Generer en person i versjon 3.0.0
Sender et post til 127.0.0.1:9993/person. Dette er svaret:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}
Stopper appen 2.0.0
Starter appen i versjon 4.0.0
Generer en person i versjon 3.0.0
Sender et post til 127.0.0.1:9993/person. Dette er svaret:
{"firstName":"cbe942fc-832e-45e9-a838-0fae25c10a51","surname":"cbe942fc-832e-45e9-a838-0fae25c10a51"}
Generer en person i versjon 4.0.0
Sender et post til 127.0.0.1:9994/person. Dette er svaret:
{"firstName":"ff6857ce-9c41-413a-863e-358e2719bf88","surname":"ff6857ce-9c41-413a-863e-358e2719bf88"}DB-endringer
Når det gjelder v3 fjerner vi bare kolonnen last_name og legger til manglende begrensninger.
-- FJERN KOLONNEN
ALTER TABLE PERSON DROP last_name;
-- LEGGE TIL BEGRENSNINGER
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;Kode-endringar
Det er ingen endringer i koden.
Utdata
Vi har vellykket rullet tilbake en inkompatibel endring av kolonnenavnet ved å utføre flere bakoverkompatible distribusjoner. Nedenfor er en oppsummering av de utførte handlingene:
- distribusjon av applikasjonen versjon
1.0.0medv1database skjema (kolonnenavn =last_name) - distribusjon av applikasjonen versjon
2.0.0,som lagrer data ilast_nameogsurname. Applikasjonen leser fralast_name. Databasen er i versjonv2, som inneholder kolonner somlast_name, så vel sometternavn. etternavner en kopi av last_name. (MERK: denne kolonnen skal ikke ha en not null begrensning) - distribusjon av applikasjonen versjon
3.0.0, som lagrer data kun isurnameog leser fra etternavn. Når det gjelder databasen, skjer den siste migreringenlast_nameisurname. Begrensningen NOT NULL fjernes fralast_name. Databasen er nå i versjonv3 - distribusjon av applikasjonen versjon
4.0.0— ingen endringer er gjort i koden. Distribusjonen av databasenv4, som sletterlast_name. Her kan du legge til eventuelle manglende begrensninger i databasen.
Ved å følge denne tilnærmingen kan du alltid rulle tilbake til en versjon uten å bryte databasen/applikasjonens kompatibilitet.
Kode
All koden som brukes i denne artikkelen er tilgjengelig på . Her er en ekstra beskrivelse.
Prosjekter
Etter å ha klonet depotet vil du se følgende mappestruktur.
├── boot-flyway-v1 - 1.0.0 versjon av appen med v1 av skjemaet
├── boot-flyway-v2 - 2.0.0 versjon av appen med v2 av skjemaet (tilbakekompatibel - appen kan rulles tilbake)
├── boot-flyway-v2-bad - 2.0.0.BAD versjon av appen med v2bad av skjemaet (tilbakekompatibel - appen kan ikke rulles tilbake)
├── boot-flyway-v3 - 3.0.0 versjon av appen med v3 av skjemaet (appen kan rulles tilbake)
└── boot-flyway-v4 - 4.0.0 versjon av appen med v4 av skjemaet (appen kan rulles tilbake)Skriptene
Du kan kjøre skriptene beskrevet i skriptene nedenfor, som vil demonstrere tilbakekompatible og inkompatible endringer i databasen.
For å se tilfellet med tilbakekompatible endringer, kjør:
./scripts/scenario_backward_compatible.shOg for å se tilfellet med tilbakekompatible endringer, kjør:
./scripts/scenario_backward_incompatible.shSpring Boot Sample Flyway
Alle eksempler er hentet fra Spring Boot Sample Flyway.
Du kan se på http://localhost:8080/flyway, der listes skriptene.
Dette eksempelet inkluderer også H2-konsollen (tilgjengelig på http://localhost:8080/h2-console), slik at du kan se tilstanden til databasen (standard jdbc URL — jdbc:h2:mem:testdb).
I tillegg
Les også andre artikler i bloggen vår:
Kilde: habr.com
