Zero geldialdi-denbora hedatzea eta datu-baseak

Zero geldialdi-denbora hedatzea eta datu-baseak

Artikulu honek zehatz-mehatz azaltzen du nola konpondu datu-baseen bateragarritasun-arazoak inplementazioan. Zure produkzio-aplikazioekin zer gerta daitekeen esango dizugu aldez aurretik prestatu gabe zabaltzen saiatzen bazara. Ondoren, zero geldialdi-denbora edukitzeko beharrezkoak diren aplikazioen bizi-zikloko faseak igaroko ditugu (gutxi gorabehera. erreia: aurrerago - zero geldialdi denbora). Gure eragiketen emaitza atzerantz bateraezin den datu-basearen aldaketa atzerakoiarekin bateragarria den era aplikatzea izango da.

Artikuluko kode-adibideak ulertu nahi badituzu, hemen aurki ditzakezu GitHub.

Sarrera

Zero geldialdi-denbora inplementatzea

Zer mistikoa zero geldialdi-denbora inplementatzea? Esan dezakezu hau zure aplikazioa zabaltzen denean aplikazioaren bertsio berri bat produkzioan arrakastaz sar dezakezun moduan, erabiltzaileak erabilgarritasunik ez duela nabaritzen duen bitartean. Erabiltzaile eta enpresaren ikuspuntutik, hau da inplementazio agertokirik onena, funtzio berriak sartzeko eta akatsak etenik gabe konpontzeko aukera ematen duelako.

Nola lortu hori? Hainbat modu daude, hona hemen horietako bat:

  • zabaldu zure zerbitzuaren 1. bertsioa
  • datu-baseen migrazioa egin
  • Inplementatu zure zerbitzuaren 2. bertsioa 1. bertsioarekin paraleloan
  • 2. bertsioak behar bezala funtzionatzen duela ikusi bezain laster, kendu 1. zenbakia
  • prest!

Erraza, ezta? Zoritxarrez, ez da hain erraza, eta hori zehatz-mehatz aztertuko dugu geroago. Orain egiazta dezagun beste inplementazio prozesu nahiko arrunt bat: inplementazio urdin berdea.

Entzun al duzu inoiz urdin berdearen hedapena? Cloud Foundry-k hau oso erraza egiten du. Ikusi besterik ez dago Artikulu hau, non hau zehatzago deskribatzen dugun. Laburbilduz, gogorarazten dizugu nola egin urdin berdearen hedapena:

  • ziurtatu zure ekoizpen kodearen bi kopia ("urdina" eta "berdea") funtzionatzen dutela;
  • trafiko guztia ingurune urdinera bideratu, hau da. ekoizpen URLek hor seinalatu dezaten;
  • aplikazio-aldaketa guztiak ingurune berde batean zabaldu eta probatu;
  • aldatu URLak ingurune urdinetik berdera

Berde urdinaren hedapena funtzio berriak erraz sartzeko aukera ematen dizun ikuspegia da, ekoizpen-hausteaz kezkatu gabe. Izan ere, zerbait gertatzen bada ere, aurreko ingurunera erraz itzuli dezakezula "etengailu bat sakatuta".

Aurreko guztia irakurri ondoren, galdera hau egin dezakezu: Zer zerikusi du zero geldialdi denborak Blue green inplementazioarekin?

Bada, komun asko dituzte, ingurune bereko bi kopia mantentzeak esfortzu bikoitza eskatzen baitu horiek mantentzeko. Horregatik diote talde batzuek Martin Fowler, jarraitu ikuspegi honen aldaera bat:

Beste aukera bat datu-base bera erabiltzea da, web eta domeinu geruzetarako etengailu urdin-berdeak sortuz. Planteamendu honetan, datu-basea arazo bat izan daiteke askotan, batez ere bere eskema aldatu behar duzunean softwarearen bertsio berri bat onartzeko.

Eta hemen artikulu honetako arazo nagusira iritsiko gara. Datu-basea. Eman diezaiogun beste begirada bat esaldi honi.

datu-baseen migrazioa egin.

Orain zure buruari galdera egin behar diozu: zer gertatzen da datu-basearen aldaketa atzerantz bateragarria ez bada? Ez al da nire aplikazioaren lehen bertsioa hautsiko? Izan ere, hauxe da gertatuko dena...

Beraz, zero geldialdi-denbora / urdin berdearen inplementazioaren onura handiak izan arren, enpresek ondorengo prozesu seguruago hau jarraitu ohi dute beren aplikazioak zabaltzeko:

  • prestatu pakete bat aplikazioaren bertsio berri batekin
  • exekutatzen ari den aplikazio bat itxi
  • exekutatu script-ak datu-basea migratzeko
  • zabaldu eta abiarazi aplikazioaren bertsio berri bat

Artikulu honetan, zure datu-basearekin eta kodearekin nola lan egin dezakezun zehaztuko dugu zero geldialdi-denbora inplementatzea aprobetxatzeko.

Datu-basearen arazoak

Datu-basean daturik gordetzen ez duen estaturik gabeko aplikazio bat baduzu, berehala lortu ahal izango duzu zero geldialdi-denbora inplementatzea. Zoritxarrez, software gehienek datuak nonbait gorde behar dituzte. Horregatik, birritan pentsatu beharko zenuke zirkuituan aldaketarik egin baino lehen. Eskema aldatzeko xehetasunetan sartu aurretik, geldialdirik gabeko inplementazioa posible izan dadin, arreta dezagun lehenik bertsioen eskeman.

Bertsio-eskema

Artikulu honetan erabiliko dugu Flyway bertsioak kontrolatzeko tresna gisa (gutxi gorabehera. Itzulpena: datu baseen migrazioez ari gara). Jakina, Spring Boot aplikazio bat ere idatziko dugu Flyway euskarria duen eta eskema migrazioa egingo du aplikazioaren testuingurua konfiguratzen duzun bitartean. Flyway erabiltzean, migrazio-scriptak zure proiektuen karpetan gorde ditzakezu (lehenespenez classpath:db/migration). Hemen migrazio fitxategi horien adibide bat ikus dezakezu

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

Adibide honetan 4 migrazio script ikusten ditugu, aurretik exekutatzen ez badira, aplikazioa abiarazten denean bata bestearen atzetik exekutatu egingo dira. Ikus dezagun fitxategietako bat (V1__init.sql) adibide gisa.

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');

Dena ezin hobeto azaltzen da: SQL erabil dezakezu zure datu-basea nola aldatu behar den definitzeko. Spring Boot eta Flyway-i buruzko informazio gehiago lortzeko, begiratu Spring Boot Docs.

Spring Boot-ekin iturburua kontrolatzeko tresna erabiliz, 2 abantaila handi lortuko dituzu:

  • datu-basearen aldaketak kode aldaketetatik bereizten dituzu
  • Datu-basearen migrazioa zure aplikazioa zabaltzearekin batera gertatzen da, hau da. zure hedapen-prozesua sinplifikatu da

Datu-basearen arazoak konpontzea

Artikuluaren hurrengo atalean, datu-baseen aldaketen bi ikuspegi aztertzera bideratuko gara.

  • atzerako bateraezintasuna
  • atzerako bateragarritasuna

Lehenengoa abisu gisa hartuko da ez duzula zero geldialdi-denbora inplementatzea aldez aurretik prestatu gabe... Bigarrenak inplementazio bat geldialdirik gabe egin dezakezun eta, aldi berean, atzerako bateragarritasuna mantentzeko irtenbide bat eskaintzen du.

Landuko dugun gure proiektua Spring Boot Flyway aplikazio sinple bat izango da Person с first_name и last_name datu-basean (gutxi gorabehera. itzulpena: Person taula bat da eta first_name и last_name - Hauek dira bertan dauden eremuak). Izena aldatu nahi dugu last_name в surname.

Hipotesiak

Xehetasunetan sartu aurretik, pare bat hipotesi egin behar ditugu gure aplikazioei buruz. Lortu nahi dugun emaitza nagusia prozesu nahiko sinplea izango da.

Oharra. Enpresa PRO-TIP. Prozesuak sinplifikatzeak diru asko aurreztu dezakezu laguntzan (zenbat eta jende gehiago izan zure enpresan lanean, orduan eta diru gehiago aurreztu dezakezu)!

Ez dago datu-basea atzera bota beharrik

Honek inplementazio-prozesua errazten du (datu-baseen itzulera batzuk ia ezinezkoak dira, hala nola, ezabatze-itzulera). Nahiago dugu aplikazioak soilik atzera botatzea. Modu honetan, datu-base desberdinak badituzu ere (adibidez, SQL eta NoSQL), zure inplementazioaren kanalizazioa berdina izango da.

BETI posible izan behar da aplikazioa bertsio bat atzera egitea (ez gehiago)

Atzera egin behar denean bakarrik egin behar da. Uneko bertsioan erraz konpontzen ez den akatsen bat badago, laneko azken bertsiora itzultzeko gai izan beharko genuke. Azken lan-bertsio hau aurrekoa dela suposatzen dugu. Kodea eta datu-baseen bateragarritasuna zabaltze bat baino gehiagorako mantentzea oso zaila eta garestia izango litzateke.

Oharra. Irakurgarritasun handiagoa lortzeko, artikulu honetan aplikazioaren bertsio nagusia aldatuko dugu.

1. urratsa: hasierako egoera

Aplikazioaren bertsioa: 1.0.0
DB bertsioa: v1

Comment

Hau izango da aplikazioaren hasierako egoera.

Datu-basearen aldaketak

DB dauka 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 aldaketak

Aplikazioak pertsonaren datuak gordetzen ditu 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
                + "]";
    }
}

Atzerantz bateraezina den zutabeen izena aldatzea

Ikus dezagun zutabe baten izena aldatzeko adibide bat:

Arreta. Ondoko adibideak nahita hautsiko ditu gauzak. Hau erakusten dugu datu-baseen bateragarritasunaren arazoa erakusteko.

Aplikazioaren bertsioa: 2.0.0.BAD

DB bertsioa: v2bad

Comment

Oraingo aldaketek EZ digute bi instantzia (zaharra eta berria) aldi berean exekutatzen uzten. Horrela, zero geldialdi-denbora zabaltzea zaila izango da lortzea (suposizioak kontuan hartzen badira, benetan ezinezkoa da).

A/B probak

Gaur egungo egoera aplikazioaren bertsio bat daukagula da 1.0.0, ekoizpenean zabalduta, eta datu-basean v1. Aplikazioaren bigarren instantzia bat zabaldu behar dugu, bertsioa 2.0.0.BAD, eta eguneratu datu-basea v2bad.

Urratsak:

  1. bertsio-aplikazioaren instantzia berri bat zabaltzen da 2.0.0.BADdatu-basea eguneratzen duena v2bad
  2. datu-basean v2bad Zutabe last_name jada ez da existitzen - hona aldatu zen surname
  3. Datu-basea eta aplikazioa eguneratzea arrakastatsua izan da eta zenbait instantzia exekutatzen ari dira 1.0.0, beste batzuk - in 2.0.0.BAD. Dena datu-basera konektatuta dago v2bad
  4. bertsioaren instantzia guztiak 1.0.0 akatsak botatzen hasiko dira zutabean datuak sartzen saiatuko direlako last_namejada existitzen ez dena
  5. bertsioaren instantzia guztiak 2.0.0.BAD arazorik gabe funtzionatuko du

Ikus dezakezunez, datu-basean eta aplikazioan atzerantz bateraezinak diren aldaketak egiten baditugu, A/B probak ezinezkoak dira.

Aplikazioa atzera botatzea

Demagun A/B inplementazioa egiten saiatu ondoren (gutxi gorabehera. per.: egileak ziurrenik A/B testing esan nahi zuen hemen) aplikazioa bertsiora itzuli behar dugula erabaki dugu 1.0.0. Demagun ez dugula datu-basea atzera egin nahi.

Urratsak:

  1. bertsio aplikazioaren instantzia gelditzen dugu 2.0.0.BAD
  2. datu-basea oraindik dago v2bad
  3. bertsioaz geroztik 1.0.0 ez du ulertzen zer den surname, akatsak ikusiko ditugu
  4. infernua askatu da, ezin dugu gehiago atzera egin

Ikus dezakezunez, datu-basean eta aplikazioan atzeraka bateraezinak diren aldaketak egiten baditugu, ezin dugu aurreko bertsiora itzuli.

Script exekuzio erregistroak

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"}

Datu-basearen aldaketak

Izena aldatzen duen migrazio-gidoia last_name в surname

Iturria Flyway gidoia:

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');

Izena aldatzen duen gidoia last_name.

-- This change is backward incompatible - you can't do A/B testing
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Kode aldaketak

Eremuaren izena aldatu dugu lastName on surname.

Zutabe bati izena aldatzea atzerakoiarekin bateragarria den moduan

Hau da topa dezakegun egoera ohikoena. Alderantziz aldaketa bateraezinak egin behar ditugu. Dagoeneko frogatu dugu zero geldialdi-denbora inplementatzeko, ez dugula datu-basearen migrazioa besterik gabe aplikatu behar urrats gehigarririk gabe. Artikuluaren atal honetan, aplikazioaren 3 inplementazio egingo ditugu datu-baseen migrazioekin batera, nahi den emaitza lortzeko, atzerako bateragarritasuna mantenduz.

Oharra. Gogoratu bertsioen datu-base bat dugula v1. Zutabeak ditu first_name и last_name. Aldatu egin behar dugu last_name on surname. Aplikazioaren bertsioa ere badugu 1.0.0, oraindik erabiltzen ez dena surname.

2. urratsa: Gehitu abizena

Aplikazioaren bertsioa: 2.0.0
DB bertsioa: v2

Comment

Zutabe berri bat gehituz eta bere edukia kopiatuz, atzerantz bateragarriak diren datu-baseen aldaketak sortzen ditugu. Aldi berean, JAR atzera egiten badugu edo JAR zahar bat martxan badugu, ez da apurtuko exekuzioan.

Bertsio berri bat kaleratzen ari gara

Urratsak:

  1. egin datu-basearen migrazioa zutabe berri bat sortzeko surname. Orain zure DB bertsioa v2
  2. kopiatu datuak last_name в surname. Arreta ezazudatu asko badituzu, loteen migrazioa kontuan hartu beharko zenuke!
  3. idatzi kodea non erabiltzen diren BIAK и berriakEta zaharrak zutabea. Orain zure aplikazioaren bertsioa 2.0.0
  4. irakurri zutabeko balioa surname, ez bada null, edo l-tikast_name, bada surname zehaztu gabea. Ezabatu dezakezu getLastName() kodeatik aterako baita null aplikaziotik atzera botatzean 3.0.0 to 2.0.0.

Spring Boot Flyway erabiltzen ari bazara, bi urrats hauek bertsioa abiaraztean egingo dira 2.0.0 aplikazioak. Datu-basearen bertsioak egiteko tresna eskuz exekutatzen baduzu, bi gauza ezberdin egin beharko dituzu horretarako (lehendabizi db bertsioa eskuz eguneratu eta gero aplikazio berria zabaldu).

Garrantzitsua da. Gogoratu sortu berri den zutabea BEHAR EZ izan EZ BALIO. Atzera itzuli bat egiten baduzu, aplikazio zaharrak ez du zutabe berria ezagutzen eta ez du instalatuko bitartean Insert. Baina murrizketa hau gehitzen baduzu eta zure db izango da v2, honek zutabe berriaren balioa ezarri beharko du. Horrek murrizketen urraketak ekarriko ditu.

Garrantzitsua da. Metodoa kendu beharko zenuke getLastName(), bertsioan 3.0.0 Kodean ez dago zutabe baten kontzepturik last_name. Horrek esan nahi du null ezarriko dela bertan. Metodoa utzi eta egiaztapenak gehi ditzakezu null, baina askoz irtenbide hobea izango litzateke logikan hori ziurtatzea getSurname() zero ez den balio zuzena hautatu duzu.

A/B probak

Gaur egungo egoera aplikazioaren bertsio bat daukagula da 1.0.0, ekoizpenean zabalduta eta datu-basean v1. Bertsio aplikazioaren bigarren instantzia bat zabaldu behar dugu 2.0.0datu-basea eguneratuko duena v2.

Urratsak:

  1. bertsio-aplikazioaren instantzia berri bat zabaltzen da 2.0.0datu-basea eguneratzen duena v2
  2. bitartean, eskaera batzuk prozesatu zituzten bertsio-instantziek 1.0.0
  3. eguneratzea arrakastatsua izan da eta bertsio-aplikazioaren hainbat instantzia exekutatzen dituzu 1.0.0 eta beste bertsio batzuk 2.0.0. Denek datu-basearekin komunikatzen dira v2
  4. Bertsio 1.0.0 ez du datu-basean abizen zutabea erabiltzen, bertsioa baizik 2.0.0 erabilerak. Ez dute elkar oztopatzen, eta ez luke akatsik egon behar.
  5. Bertsio 2.0.0 datuak zutabe zaharrean zein berrian gordetzen ditu, atzerako bateragarritasuna bermatuz

Garrantzitsua da. Zutabe zahar/berriko balioetan oinarritutako elementuak zenbatzen dituen kontsultarik baduzu, gogoratu behar duzu orain balio bikoiztuak dituzula (seguruenik migratzen ari direla oraindik). Adibidez, abizena (zutabea deitzen den edozein dela ere) letraz hasten den erabiltzaile kopurua zenbatu nahi baduzu. A, gero datuen migrazioa amaitu arte (oldnew zutabea) datu koherenteak izan ditzakezu zutabe berri bat kontsultatzen baduzu.

Aplikazioa atzera botatzea

Orain aplikazioaren bertsioa dugu 2.0.0 eta datu-basean v2.

Urratsak:

  1. itzuli zure aplikazioa bertsiora 1.0.0.
  2. Bertsio 1.0.0 ez du zutaberik erabiltzen datu-basean surname, beraz, atzera egiteak arrakasta izan behar du

DB aldaketak

Datu-baseak izeneko zutabe bat dauka last_name.

Flyway iturriko gidoia:

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');

Gehitu gidoia surname.

Arreta. Gogoan izan EZIN DIRA GEHITU NOT NULL mugarik gehitzen ari zaren zutabean. JAR atzera egiten baduzu, bertsio zaharrak ez du gehitutako zutabeari buruzko ideiarik izango eta automatikoki NULL ezarriko du. Muga hori badago, aplikazio zaharra hautsiko da.

-- NOTE: This field can't have the NOT NULL constraint cause if you rollback, the old version won't know about this field
-- and will always set it to NULL
ALTER TABLE PERSON ADD surname varchar(255);

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Kode aldaketak

Datuak bezala gordetzen ditugu last_name, eta surname. Aldi berean irakurtzen dugu last_name, zutabe hau garrantzitsuena baita. Inplementazio-prozesuan, baliteke eskaera batzuk oraindik eguneratu ez den aplikazio-instantzia batek prozesatu izana.

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

3. urratsa: abizena kodeatik kentzea

Aplikazioaren bertsioa: 3.0.0

DB bertsioa:v3

Comment

Ohar per.: Dirudienez, jatorrizko artikuluan egileak bloke honen testua oker kopiatu zuen 2. urratsetik. Urrats honetan, aldaketak egin behar dira aplikazioaren kodean zutabea erabiltzen duen funtzionaltasuna kentzera zuzenduta. last_name.

Zutabe berri bat gehituz eta bere edukia kopiatuz, atzerantz bateragarriak diren datu-baseen aldaketak sortu ditugu. Gainera, JAR atzera egiten badugu edo JAR zahar bat martxan badugu, ez da apurtuko exekuzioan.

Aplikazioa atzera botatzea

Une honetan aplikazioaren bertsioa dugu 3.0.0 eta datu-basea v3. Bertsioa 3.0.0 ez ditu datuak gordetzen last_name. Horrek esan nahi du barruan surname informazio eguneratuena gordetzen da.

Urratsak:

  1. itzuli zure aplikazioa bertsiora 2.0.0.
  2. Bertsio 2.0.0 erabilerak eta last_name и surname.
  3. Bertsio 2.0.0 hartuko du surname, zero ez bada, bestela -last_name

Datu-basearen aldaketak

Datu-basean ez dago egitura-aldaketarik. Script hau exekutatzen da datu zaharren azken migrazioa egiteko:

-- 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;

Kode aldaketak

Ohar per.: Bloke honen deskribapena ere oker kopiatu zuen egileak 2. urratsetik. Artikuluaren logikaren arabera, urrats honetako kodean aldaketak zutabearekin lan egiten duten elementuak kentzera zuzendu behar dira. last_name.

Datuak bezala gordetzen ditugu last_name, eta surname. Gainera, zutabetik irakurri dugu last_name, garrantzitsuena baita. Inplementazio prozesuan, eskaera batzuk oraindik eguneratu ez den instantzia batek prozesatu ditzake.

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

4. urratsa: abizena datu-basetik kentzea

Aplikazioaren bertsioa: 4.0.0

DB bertsioa: v4

Comment

Bertsio-kodea dela eta 3.0.0 ez zuen zutabea erabili last_name, ez da ezer txarrik gertatuko exekuzioan atzera egiten badugu 3.0.0 zutabe bat datu-basetik kendu ondoren.

Script exekuzio erregistroak

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 aldaketak

Erlatiboki v3 zutabea kendu besterik ez dugu egiten last_name eta gehitu falta diren murrizketak.

-- 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;

Kode aldaketak

Ez dago kodean aldaketarik.

Irteera

Alderantziz bateraezinak diren zutabe-izen aldaketa behar bezala aplikatu dugu atzerantz bateragarriak diren hainbat inplementazio eginez. Jarraian, egindako ekintzen laburpena da:

  1. aplikazioaren bertsioa zabaltzea 1.0.0 с v1 datu-basearen eskema (zutabearen izena = last_name)
  2. aplikazioaren bertsioa zabaltzea 2.0.0, datuak gordetzen dituena last_name и surname. Aplikazioak irakurtzen du last_name. Datu-basea bertsioan dago v2bezalako zutabeak dituztenak last_nameEta surname. surname l-ren kopia daast_name. (OHARRA: zutabe honek ez du mugarik ez nulurik izan behar)
  3. aplikazioaren bertsioa zabaltzea 3.0.0, datuak bakarrik gordetzen dituena surname eta abizenetik irakurtzen da. Datu-baseari dagokionez, azken migrazioa egiten ari da last_name в surname. Muga bat ere EZ BALIO kenduta last_name. Datu-basea bertsioan dago orain v3
  4. aplikazioaren bertsioa zabaltzea 4.0.0 - kodean ez da aldaketarik egiten. Datu-basearen hedapena v4, kentzen duena last_name. Hemen datu-basean falta diren mugak gehi ditzakezu.

Ikuspegi hau jarraituz, beti bertsio bat atzera egin dezakezu datu-basearen/aplikazioen bateragarritasuna hautsi gabe.

Code

Artikulu honetan erabilitako kode guztia helbidean dago eskuragarri Github. Jarraian deskribapen gehigarria dago.

proiektuen

Biltegia klonatu ondoren, karpeta-egitura hau ikusiko duzu.

├── 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)

Gidoiak

Beheko scriptetan deskribatutako script-ak exekutatu ditzakezu, datu-basean atzerakoiarekin bateragarriak diren eta bateraezinak diren aldaketak erakutsiko dituztenak.

Ikusi atzerantz bateragarriak diren aldaketekin kasua, Korrika egin:

./scripts/scenario_backward_compatible.sh

Eta ikusteko atzerantz bateraezinak diren aldaketak dituen kasua, Korrika egin:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Adibide guztiak hemendik hartuak dira Spring Boot Sample Flyway.

Begirada bat eman diezaiokezu http://localhost:8080/flyway, gidoien zerrenda dago.

Adibide honek H2 kontsola ere barne hartzen du (at http://localhost:8080/h2-console) datu-basearen egoera ikusi ahal izateko (jdbc URL lehenetsia da jdbc:h2:mem:testdb).

gainera

Irakurri beste artikulu batzuk ere gure blogean:

Iturria: www.habr.com

Gehitu iruzkin berria