Zero Downtime Deployment i baze podataka

Zero Downtime Deployment i baze podataka

Ovaj članak detaljno objašnjava kako riješiti probleme s kompatibilnošću baza podataka prilikom implementacije. Objasnit ćemo što se može dogoditi s vašim aplikacijama u produkciji ako pokušate implementirati bez prethodne pripreme. Nakon toga ćemo proći kroz faze životnog ciklusa aplikacije koje su potrebne za postizanje nultog vremena zastoja (napomena: dalje - zero downtime). Rezultat naših operacija bit će primjena promjene baze podataka koja nije kompatibilna unatrag na kompatibilan način.

Ako želite proučiti primjere koda iz članka, pronaći ćete ih na GitHub.

Uvod

Zero downtime deployment

Što je to mistično zero downtime deployment? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.

Kako to postići? Postoji nekoliko načina, evo jednog od njih:

  • implementirajte verziju br. 1 vašeg servisa
  • izvršite migraciju baze podataka
  • implementirajte verziju br. 2 vašeg servisa paralelno s verzijom br. 1
  • kada vidite da verzija br. 2 radi kako treba, uklonite verziju br. 1
  • spremno!

Lako, zar ne? Nažalost, nije tako jednostavno, a kasnije ćemo to detaljnije razmotriti. A sada hajde da provjerimo još jedan prilično često korišten proces implementacije - blue green deployment.

Jeste li ikada čuli za blue green deployment? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на ovaj članak, gdje to detaljnije opisujemo. Ukratko, ponovimo kako raditi blue green deployment:

  • osigurajte rad dviju kopija vašeg produkcijskog koda (“blue” i “green”);
  • usmjerite sav promet prema blue okruženju, tj. da URL adrese produkcije upućuju tamo;
  • implementirajte i testirajte sve promjene aplikacije u green okruženju;
  • prebacite URL adrese s blue na green okruženje

Blue green deployment je pristup koji vam omogućuje lako uvođenje novih funkcija, bez brige da će produkcija biti pokvarena. To je zato što, čak i ako nešto pođe po zlu, možete lako preći na prethodno okruženje jednostavno ‘prebacivanjem prekidača’.

Nakon što ste pročitali sve gore navedeno, mogli biste se zapitati: Kakve veze zero downtime ima s blue green implementacijom?

Pa, imaju prilično mnogo zajedničkog, budući da podrška dvjema kopijama istog okruženja zahtijeva dvostruke napore za njihovo održavanje. Zato neke ekipe, kako tvrdi Martin Fowler, drže se varijacije ovog pristupa:

druga opcija uključuje korištenje iste baze podataka, stvarajući plavo-zelene preklopnike za web i domenske slojeve. U takvom pristupu baze podataka često mogu predstavljati problem, posebno kada trebate promijeniti njezinu shemu kako biste podržali novu verziju softvera.

I ovdje dolazimo do glavnog problema u ovom članku. Baza podataka. Pogledajmo ponovno ovu frazu.

izvršite migraciju baze podataka.

Sada biste se trebali zapitati — što ako promjena baze podataka nije kompatibilna? Hoće li moja prva verzija aplikacije propasti? Zapravo, to će se i dogoditi...

Dakle, čak i unatoč ogromnim prednostima zero downtime / blue green deployment-a, tvrtke se sklone pridržavati sljedećeg sigurnijeg procesa implementacije svojih aplikacija:

  • pripremiti paket s novom verzijom aplikacije
  • isključiti pokrenutu aplikaciju
  • pokrenuti skripte za migraciju baze podataka
  • implementirati i pokrenuti novu verziju aplikacije

U ovom ćemo članku detaljno opisati kako možete raditi s bazom podataka i kodom kako biste iskoristili prednosti zero downtime deployment-a.

Problemi s bazom podataka

Ako imate stateless aplikaciju koja ne pohranjuje nikakve podatke u Bazi podataka, možete odmah dobiti zero downtime deployment. Nažalost, velika većina softvera mora negdje pohraniti podatke. Zato trebate dvaput razmisliti prije nego što izvršite bilo kakve promjene u shemi. Prije nego što se duboko zaronimo u detalje kako promijeniti shemu na način koji omogućuje implementaciju bez zastoja, prvo se usredotočimo na shemu upravljanja verzijama.

Shema upravljanja verzijama

U ovom ćemo članku koristiti Flyway kao alat za upravljanje verzijama (napomena: radi se o migracijama baze podataka). Naravno, također ćemo napisati Spring Boot aplikaciju koja ima ugrađenu podršku za Flyway i izvršava migraciju sheme tijekom postavljanja konteksta aplikacije. Kada koristite Flyway, možete pohraniti skripte migracije u mapu vaših projekata (po defaultu u classpath:db/migration). Ovdje možete vidjeti primjer takvih datoteka migracije

└── db
 └── migration
     ├── V1__init.sql
     ├── V2__Add_surname.sql
     ├── V3__Final_migration.sql
     └── V4__Remove_lastname.sql

U ovom primjeru vidimo 4 scenarija migracije koji, ako nisu ranije izvršeni, bit će izvršeni jedan za drugim prilikom pokretanja aplikacije. Pogledajmo jednu od datoteka (V1__init.sql) kao primjer.

KREIRAJ TABLICU OSOBA (
id BIGINT GENERIRAN PO ZADANOJ POSTAVCI KAO IDENTITET,
ime varchar(255) ne može biti NULL,
prezime varchar(255) ne može biti NULL
);

umetni u OSOBA (ime, prezime) vrijednosti ('Dave', 'Syer');

Sve savršeno govori samo za sebe: možete koristiti SQL za definiranje kako vaša baza podataka treba biti promijenjena. Za više informacija o Spring Bootu i Flywayu, pogledajte Spring Boot dokumentacija.

Korištenjem alata za upravljanje verzijama sa Spring Bootom, dobivate dvije velike prednosti:

  • odvajate promjene u bazi podataka od promjena u kodu
  • migracija baze podataka se događa zajedno s puštanjem vaše aplikacije, tj. vaš proces implementacije se pojednostavljuje

Rješavanje problema s bazom podataka

U sljedećem dijelu članka usredotočit ćemo se na dva pristupa promjenama u bazi podataka.

  • povratna nekompatibilnost
  • povratna kompatibilnost

Prvi će biti razmatran kao upozorenje da ne trebate provoditi zero downtime deployment bez prethodne pripreme… Drugi nudi rješenje kako možete izvršiti implementaciju bez zastoja i istovremeno održavati povratnu kompatibilnost.

Naš projekt na kojem ćemo raditi bit će jednostavna aplikacija Spring Boot Flyway koja ima Osoba s ime i prezime u bazi podataka (napomena: Osoba je tablica, aime i prezime – to su polja unutar nje). Želimo preimenovati prezime u prezime.

Pretpostavke

Prije nego što se upustimo u detalje, potrebno je postaviti nekoliko pretpostavki u vezi s našim aplikacijama. Glavni rezultat koji želimo postići bit će prilično jednostavan proces.

Napomena. Business PRO-TIP. Pojednostavljenje procesa može vam uštedjeti puno novca na održavanju (što više ljudi radi u vašoj tvrtki, više novca možete uštedjeti)!

Ne trebate raditi povrat baze podataka

To pojednostavljuje proces implementacije (neki povrati baze podataka su praktički nemogući, na primjer povrat brisanja). Preferiramo vraćanje samo aplikacija. Tako, čak i ako imate različite baze podataka (npr. SQL i NoSQL), vaš deployment pipeline će izgledati jednako.

Treba imati SVAKADA mogućnost vraćanja aplikacije na jednu verziju unatrag (ne više)

Povratak se treba izvoditi samo po potrebi. Ako trenutna verzija ima grešku koju nije lako ispraviti, trebamo imati mogućnost ponovnog vraćanja na posljednju radnu verziju. Pretpostavljamo da je ta posljednja radna verzija prethodna. Održavanje kompatibilnosti koda i baze podataka za više od jednog izdanja bilo bi izuzetno teško i skupo.

Napomena. Za veću čitljivost, u okviru ovog članka promijenit ćemo glavnu verziju aplikacije.

Korak 1: Izvorno stanje

Verzija aplikacije: 1.0.0
Verzija Baze podataka: v1

Komentar

Ovo će biti izvorno stanje aplikacije.

Promjene Baze podataka

Baza podataka sadrži last_name.

KREIRAJ TABLICU OSOBA (
    id BIGINT GENERISAN PO ZADATKU KAO IDENTITET,
    first_name varchar(255) NOT NULL,
    last_name varchar(255) NOT NULL
);

umetni u OSOBE (first_name, last_name) vrijednosti ('Dave', 'Syer');

Promjene koda

Aplikacija skladišti podatke o osobi u prezime:

/*
 * 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
                + "]";
    }
}

Povratno nekompatibilno preimenovanje stupca

Razmotrimo primjer kako promijeniti ime stupca:

Pažnja. Sljedeći primjer namjerno će dovesti do pogreške. Prikazujemo to kako bismo demonstrirali problem kompatibilnosti baze podataka.

Verzija aplikacije: 2.0.0.BAD

Verzija Baze podataka: v2bad

Komentar

Trenutne promjene NE dopuštaju nam pokretanje dva instanca (stare i nove) istovremeno. Stoga će zero downtime deployment biti teško postići (uzimajući u obzir pretpostavke, to je zapravo nemoguće).

A/B testiranje

Trenutna situacija je takva da imamo aplikaciju verzije 1.0.0, razvijena u produkciji, i Baza podataka v1. Moramo rasporediti drugi primjerak aplikacije, verzije 2.0.0.BAD, i ažurirati bazu podataka na v2bad.

Koraci:

  1. raspoređen je novi primjerak aplikacije verzije 2.0.0.BAD, koji ažurira bazu podataka na v2bad
  2. u bazi podataka v2bad stupac prezime više ne postoji — promijenjen je na prezime
  3. ažuriranje baze podataka i aplikacije je uspješno prošlo, i neki primjerci rade u 1.0.0, drugi — u 2.0.0.BAD. Svi su povezani s bazom podataka v2bad
  4. svi primjerci verzije 1.0.0 počet će davati greške, jer će pokušati umetnuti podatke u stupac prezime, koji više ne postoji
  5. svi primjerci verzije 2.0.0.BAD će raditi bez problema

Kao što vidite, ako napravimo povratno nekompatibilne promjene u bazi podataka i aplikaciji, A/B testiranje je nemoguće.

Povrat aplikacije

Pretpostavimo da nakon pokušaja izvršiti A/B deployment (napomena: vjerovatno je autor ovdje mislio na A/B testiranje) odlučimo da trebamo vratiti aplikaciju na verziju 1.0.0. Pretpostavimo da ne želimo napraviti povratak baze podataka.

Koraci:

  1. zaustavljamo instancu aplikacije verzije 2.0.0.BAD
  2. baza podataka je još uvijek v2bad
  3. jer verzija 1.0.0 ne razumije što je prezime, vidjet ćemo pogreške
  4. pakao je pobijedio, više se ne možemo vratiti

Kao što vidite, ako napravimo unatrag nespojive promjene u BDP i aplikaciji, ne možemo se vratiti na prethodnu verziju.

Logovi izvođenja skripte

Scenarij unatrag nespojiv:

01) Pokrenite 1.0.0
02) Pričekajte da se aplikacija (1.0.0) pokrene
03) Generirajte osobu pozivom POST localhost:9991/person na verziju 1.0.0
04) Pokrenite 2.0.0.BAD
05) Pričekajte da se aplikacija (2.0.0.BAD) pokrene
06) Generirajte osobu pozivom POST localhost:9991/person na verziju 1.0.0 <-- ovo bi trebalo propasti
07) Generirajte osobu pozivom POST localhost:9992/person na verziju 2.0.0.BAD <-- ovo bi trebalo proći

Pokretanje aplikacije u verziji 1.0.0
Generiranje osobe u verziji 1.0.0
Slanje posta na 127.0.0.1:9991/person. Ovo je odgovor:

{"firstName":"b73f639f-e176-4463-bf26-1135aace2f57","lastName":"b73f639f-e176-4463-bf26-1135aace2f57"}

Pokretanje aplikacije u verziji 2.0.0.BAD
Generiranje osobe u verziji 1.0.0
Slanje posta na 127.0.0.1:9991/person. Ovo je odgovor:

curl: (22) Zahtjevani URL vratio grešku: 500 Interna greška poslužitelja

Generiranje osobe u verziji 2.0.0.BAD
Slanje posta na 127.0.0.1:9995/person. Ovo je odgovor:

{"firstName":"e156be2e-06b6-4730-9c43-6e14cfcda125","surname":"e156be2e-06b6-4730-9c43-6e14cfcda125"}

Promjene Baze podataka

Skripta za migraciju koja preimenuje prezime u prezime

Izvorna Flyway skripta:

KREIRAJ TABLICU OSOBA (
    id BIGINT GENERISAN PO ZADATKU KAO IDENTITET,
    first_name varchar(255) NOT NULL,
    last_name varchar(255) NOT NULL
);

umetni u OSOBE (first_name, last_name) vrijednosti ('Dave', 'Syer');

Skripta koja preimenuje prezime.

-- Ova promjena je unatrag nespojiva - ne možete provoditi A/B testiranje
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Promjene koda

Promijenili smo ime polja lastName na prezime.

Preimenovanje stupca unatrag kompatibilnim načinom

Ovo je najčešća situacija s kojom se možemo susresti. Moramo provesti unatrag nespojive promjene. Već smo dokazali da za implementaciju bez zastoja ne bismo trebali samo primjenjivati migraciju baze podataka bez dodatnih radnji. U ovom dijelu članka napravit ćemo 3 implementacije aplikacije zajedno s migracijama baze podataka kako bismo postigli željeni rezultat i zadržali unatrag kompatibilnost.

Napomena. Podsjetimo se da imamo BDP verzije v1. Sadrži stupce ime i prezime. Moramo promijeniti prezime na prezime. Također imamo aplikaciju verzije 1.0.0, koja još ne koristi prezime.

Korak 2: Dodavanje surname

Verzija aplikacije: 2.0.0
Verzija Baze podataka: v2

Komentar

Dodajući novi stupac i kopirajući njegov sadržaj, stvaramo unatrag kompatibilne promjene u BDP-u. U isto vrijeme, ako vratimo JAR ili imamo radni stari JAR, neće se pokvariti tijekom izvođenja.

Objavljujemo novu verziju

Koraci:

  1. izvršite migraciju BDP-a, kako biste stvorili novi stupac prezime. Sada je vaša BDP verzija v2
  2. kopirajte podatke iz prezime u prezime. Napominjemo, što ako imate puno ovih podataka, trebali biste razmotriti paketnu migraciju!
  3. napisite kod gdje se koriste OBA i novi, i stari stupac. Sada vaša aplikacija verzije 2.0.0
  4. pročitajte vrijednost iz stupca prezime, ako nije null, ili iz last_name, ako prezime nije zadano. Možete ukloniti getLastName() iz koda, jer će vraćati null pri vraćanju vaše aplikacije s 3.0.0 do 2.0.0.

Ako koristite Spring Boot Flyway, ova dva koraka će se izvršiti prilikom pokretanja verzije 2.0.0 aplikacije. Ako ručno pokrećete alat za upravljanje verzijama baze podataka, morat ćete napraviti ta dva različita koraka (prvo ručno ažurirajte verziju baze podataka, a zatim postavite novu aplikaciju).

Važno. Zapamtite da novi stupac NE SMIJE biti NOT NULL. Ako radite vraćanje, stara aplikacija ne zna za novi stupac i neće ga postaviti tijekom Insert. Ali ako dodate ovo ograničenje, a vaša baza podataka će biti v2, to će zahtijevati postavljanje vrijednosti novog stupca. Što će dovesti do kršenja ograničenja.

Važno. Trebali biste ukloniti metodu getLastName(), budući da u verziji 3.0.0 u kodu ne postoji pojam stupca prezime. To znači da će tamo biti postavljeni null. Možete zadržati metodu i dodati provjere na null, ali je puno bolje rješenje osigurati da ste u logici getSurname() odabrali ispravnu nenull vrijednost.

A/B testiranje

Trenutna situacija je takva da imamo aplikaciju verzije 1.0.0, implementirano na produkciji, i baza podataka u v1. Moramo implementirati drugu instancu aplikacije verzije 2.0.0, koja će ažurirati bazu podataka do v2.

Koraci:

  1. raspoređen je novi primjerak aplikacije verzije 2.0.0, koji ažurira bazu podataka na v2
  2. ujedno su neki upiti obrađivani instancama verzije 1.0.0
  3. a ažuriranje je prošlo uspješno, i imate nekoliko radnih instanci aplikacije verzije 1.0.0 i ostalih verzija 2.0.0. Svi komuniciraju s bazom podataka u v2
  4. verzija 1.0.0 ne koristi u bazi podataka stupac surname, a verzija 2.0.0 koristi. Oni se ne ometaju međusobno, i ne bi trebale biti greške.
  5. verzija 2.0.0 pohranjuje podatke i u starom i u novom stupcu, što osigurava unazadnu kompatibilnost

Važno. Ako imate bilo kakve upite koji broje stavke na temelju vrijednosti iz starog / novog stupca, trebali biste zapamtiti da sada imate duplicirane vrijednosti (najvjerojatnije se još uvijek migriraju). Na primjer, ako želite prebrojati broj korisnika čija prezimena (kako god se zvao stupac) počinju slovom A, do završetka migracije podataka (old → new Možete imati neusklađene podatke ako izvršavate upit na novom stupcu.

Povrat aplikacije

Trenutno imamo aplikaciju verzije 2.0.0 i bazu podataka u v2.

Koraci:

  1. vratite svoju aplikaciju na verziju 1.0.0.
  2. verzija 1.0.0 ne koristi stupac u bazi podataka prezime, tako da bi povratak trebao biti uspješan.

Promjene baze podataka

Baza podataka sadrži stupac pod nazivom prezime.

Izvorni Flyway skript:

KREIRAJ TABLICU OSOBA (
    id BIGINT GENERISAN PO ZADATKU KAO IDENTITET,
    first_name varchar(255) NOT NULL,
    last_name varchar(255) NOT NULL
);

umetni u OSOBE (first_name, last_name) vrijednosti ('Dave', 'Syer');

Skript za dodavanje prezime.

Pažnja. Zapamtite da NE TREBA dodavati nikakva ograničenja NOT NULL na dodani stupac. Ako vratite JAR, stara verzija neće znati za dodani stupac i automatski će mu postaviti vrijednost NULL. U slučaju da takvo ograničenje postoji, stara aplikacija će jednostavno puknuti.

-- NAPOMENA: Ovo polje ne može imati ograničenje NOT NULL jer, ako se povuče, stara verzija neće znati za ovo polje
-- i uvijek će ga postaviti na NULL
ALTER TABLE OSOBA DODAJ prezime varchar(255);

-- PRETPOSTAVLJAMO DA JE TO BRZA MIGRACIJA - U SUPROTNOM BIH MORALE MIGRIRATI U SERIJAMA
UPDATE OSOBA POSTAVI OSOBA.prezime = OSOBA.prezime;

Promjene koda

Skladištimo podatke kako u prezime, tako i u prezime. Pri tome čitamo iz prezime, jer je ovaj stupac najaktuelniji. Tokom implementacije, neki upiti mogli su biti obrađeni instancom aplikacije koja još nije ažurirana.

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;
    private String surname;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    /**
     * Reading from the new column if it's set. If not the from the old one.
     *
     * When migrating from version 1.0.0 -> 2.0.0 this can lead to a possibility that some data in
     * the surname column is not up to date (during the migration process lastName could have been updated).
     * In this case one can run yet another migration script after all applications have been deployed in the
     * new version to ensure that the surname field is updated.
     *
     * However it makes sense since when looking at the migration from 2.0.0 -> 3.0.0. In 3.0.0 we no longer
     * have a notion of lastName at all - so we don't update that column. If we rollback from 3.0.0 -> 2.0.0 if we
     * would be reading from lastName, then we would have very old data (since not a single datum was inserted
     * to lastName in version 3.0.0).
     */
    public String getSurname() {
        return this.surname != null ? this.surname : this.lastName;
    }

    /**
     * Storing both FIRST_NAME and SURNAME entries
     */
    public void setSurname(String surname) {
        this.lastName = surname;
        this.surname = surname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", lastName=" + this.lastName + ", surname=" + this.surname
                + "]";
    }
}

Korak 3: Uklanjanje last_name iz koda

Verzija aplikacije: 3.0.0

Verzija Baze podataka:v3

Komentar

Napomena prev.: Očigledno, u izvornom članku autor je greškom kopirao tekst ovog bloka iz koraka 2. U ovom koraku trebaju se izvršiti izmjene u kodu aplikacije usmjerene na uklanjanje funkcionalnosti koja koristi stupac prezime.

Dodavanjem novog stupca i kopiranjem njegovog sadržaja, stvorili smo unazad kompatibilne promjene u bazi podataka. Također, ako povučemo JAR ili imamo funkcionalni stari JAR, on se neće slomiti tokom izvršenja.

Povrat aplikacije

Trenutno imamo aplikaciju verzije 3.0.0 i bazu podataka v3. Verzija 3.0.0 ne čuva podatke u prezime. To znači da u prezime se drži najaktuelnija informacija.

Koraci:

  1. vratite svoju aplikaciju na verziju 2.0.0.
  2. verzija 2.0.0 koristi i prezime i prezime.
  3. verzija 2.0.0 uzeti će prezime, ako nije nula, inače —prezime

Promjene Baze podataka

U bazi podataka nema strukturnih promjena. Izvršava se sljedeći skript koji provodi konačnu migraciju starih podataka:

-- PRETPOSTAVLJAMO DA JE TO BRZA MIGRACIJA - U SUPROTNOM BIH MORALE MIGRIRATI U SERIJAMA
-- TAKOĐE NE PROVERAVAMO DA LI NE PREKRAJAMO POSTOJEĆE UNOSE. MORALE BIH UPOREDITI
-- VERSIJE UNOSA DA ZALOŽIMO DA AKO VEĆ POSTOJI UNOS SA VIŠIM BROJEM VERZIJE
-- NEĆEMO GA PREKLAPATI.
UPDATE OSOBA POSTAVI OSOBA.prezime = OSOBA.prezime;

-- ODBACIVANJE OGRANIČENJA NOT NULL; U SUPROTNOM ĆETE POKUŠATI UMETNUTI NULL VREDNOST PREZIME
-- SA OGRANIČENJEM NOT NULL.
ALTER TABLE OSOBA MODIFICIRAJ KOLONU prezime varchar(255) NULL DEFAULT NULL;

Promjene koda

Napomena: Opis ove jedinice je također pogrešno preuzet od strane autora s koraka 2. Prema logici narativa članka, izmjene u kodu na ovom koraku trebaju biti usmjerene na uklanjanje elemenata koji upravljaju kolonama. prezime.

Podatke čuvamo kako u prezime, tako i u prezime. Osim toga, čitamo iz kolone prezime, jer je ona najrelevantnija. Tijekom implementacije, neki zahtjevi mogu biti obrađeni instancom koja još nije ažurirana.

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String surname;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getSurname() {
        return this.surname;
    }

    public void setSurname(String lastname) {
        this.surname = lastname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", surname=" + this.surname
                + "]";
    }
}

Korak 4: Uklanjanje last_name iz Baze Podataka

Verzija aplikacije: 4.0.0

Verzija Baze podataka: v4

Komentar

S obzirom na to da kod verzije 3.0.0 nije koristio kolonu prezime, tijekom izvršenja neće se dogoditi ništa loše ako se vratimo na 3.0.0 nakon uklanjanja kolone iz baze podataka.

Logovi izvođenja skripte

Provest ćemo to na sljedeći način:

01) Pokrenite 1.0.0
02) Sačekajte da aplikacija (1.0.0) pokrene
03) Generirajte osobu pozivanjem POST localhost:9991/person za verziju 1.0.0
04) Pokrenite 2.0.0
05) Sačekajte da aplikacija (2.0.0) pokrene
06) Generirajte osobu pozivanjem POST localhost:9991/person za verziju 1.0.0
07) Generirajte osobu pozivanjem POST localhost:9992/person za verziju 2.0.0
08) Ugasite aplikaciju (1.0.0)
09) Pokrenite 3.0.0
10) Sačekajte da aplikacija (3.0.0) pokrene
11) Generirajte osobu pozivanjem POST localhost:9992/person za verziju 2.0.0
12) Generirajte osobu pozivanjem POST localhost:9993/person za verziju 3.0.0
13) Ugasite aplikaciju (3.0.0)
14) Pokrenite 4.0.0
15) Sačekajte da aplikacija (4.0.0) pokrene
16) Generirajte osobu pozivanjem POST localhost:9993/person za verziju 3.0.0
17) Generirajte osobu pozivanjem POST localhost:9994/person za verziju 4.0.0

Pokretanje aplikacije u verziji 1.0.0
Generiranje osobe u verziji 1.0.0
Slanje posta na 127.0.0.1:9991/person. Ovo je odgovor:

{"firstName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2","lastName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2"}

Pokretanje aplikacije u verziji 2.0.0

Generiranje osobe u verziji 1.0.0
Slanje posta na 127.0.0.1:9991/person. Ovo je odgovor:

{"firstName":"e41ee756-4fa7-4737-b832-e28827a00deb","lastName":"e41ee756-4fa7-4737-b832-e28827a00deb"}

Generiranje osobe u verziji 2.0.0
Slanje posta na 127.0.0.1:9992/person. Ovo je odgovor:

{"firstName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","lastName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","surname":"0c1240f5-649a-4bc5-8aa9-cff855f3927f"}

Gašenje aplikacije 1.0.0

Pokretanje aplikacije u verziji 3.0.0

Generiranje osobe u verziji 2.0.0
Slanje posta na 127.0.0.1:9992/person. Ovo je odgovor:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}

Generiranje osobe u verziji 3.0.0
Slanje posta na 127.0.0.1:9993/person. Ovo je odgovor:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}

Gašenje aplikacije 2.0.0

Pokretanje aplikacije u verziji 4.0.0

Generiranje osobe u verziji 3.0.0
Slanje posta na 127.0.0.1:9993/person. Ovo je odgovor:

{"firstName":"cbe942fc-832e-45e9-a838-0fae25c10a51","surname":"cbe942fc-832e-45e9-a838-0fae25c10a51"}

Generiranje osobe u verziji 4.0.0
Slanje posta na 127.0.0.1:9994/person. Ovo je odgovor:

{"firstName":"ff6857ce-9c41-413a-863e-358e2719bf88","surname":"ff6857ce-9c41-413a-863e-358e2719bf88"}

Izmjene Baze Podataka

U vezi s tim v3 samo uklanjamo kolonu prezime i dodajemo nedostajuća ograničenja.

-- Uklonite stupac
ALTER TABLE PERSON DROP last_name;

-- Dodajte ograničenja
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Promjene koda

Nema promjena u kodu.

Izvještaj

Uspješno smo primijenili povratno nekompatibilnu promjenu imena stupca, izvršavajući nekoliko povratno kompatibilnih isporuka. Ispod je sažetak izvršenih radnji:

  1. isporuka aplikacije verzije 1.0.0 s v1 sheme Baze podataka (ime stupca = prezime)
  2. isporuka aplikacije verzije 2.0.0, koje čuva podatke u prezime i prezime. Aplikacija čita iz prezime. Baza podataka je u verziji v2, koja sadrži stupce kao prezime, kao i surname. surname je kopija last_name. (NAPOMENA: ovaj stupac ne bi trebao imati ograničenje not null)
  3. isporuka aplikacije verzije 3.0.0, koji čuva podatke samo u prezime i čita iz surname. Što se tiče Baze podataka, izvršava se posljednja migracija prezime u prezime. Također, ograničenje NOT NULL uklanja se s prezime. Baza podataka je sada u verziji v3
  4. isporuka aplikacije verzije 4.0.0 — u kodu nisu izvršene nikakve promjene. Isporuka baze podataka v4, koja uklanja prezime. Ovdje možete dodati sva nedostajuća ograničenja u Bazi podataka.

Slijedeći ovaj pristup, uvijek se možete vratiti na jednu verziju unazad, ne kršeći kompatibilnost baze podataka / aplikacije.

Kod

Sav kod korišten u ovom članku dostupan je na Github. Ispod je dodatni opis.

Projekti

Nakon kloniranja repozitorija, vidjet ćete sljedeću strukturu mapa.

├── boot-flyway-v1              - 1.0.0 verzija aplikacije sa v1 shemom
├── boot-flyway-v2              - 2.0.0 verzija aplikacije sa v2 shemom (povratno kompatibilna - aplikaciju je moguće vratiti)
├── boot-flyway-v2-bad          - 2.0.0.BAD verzija aplikacije sa v2bad shemom (povratno nekompatibilna - aplikaciju nije moguće vratiti)
├── boot-flyway-v3              - 3.0.0 verzija aplikacije sa v3 shemom (aplikaciju je moguće vratiti)
└── boot-flyway-v4              - 4.0.0 verzija aplikacije sa v4 shemom (aplikaciju je moguće vratiti)

Skripte

Možete pokrenuti skripte opisane u donjim skriptama, koje će demonstrirati povratno kompatibilne i nekompatibilne promjene u Bazi podataka.

Da biste vidjeli slučaj s povratno kompatibilnim promjenama, pokrenite:

./scripts/scenario_backward_compatible.sh

A da biste vidjeli slučaj s povratno nekompatibilnim promjenama, pokrenite:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Svi primjeri su preuzeti iz Spring Boot Sample Flyway.

Možete pogledati http://localhost:8080/flyway, tamo je popis skripti.

Ovaj primjer također uključuje H2 konzolu (na adresi http://localhost:8080/h2-console), tako da možete pregledavati stanje baze podataka (URL jdbc po defaultu — jdbc:h2:mem:testdb).

Dodatno

Također pročitajte druge članke na našem blogu:

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster