Nulles dīkstāves izvietošana un datu bāzes

Nulles dīkstāves izvietošana un datu bāzes

Šajā rakstā ir detalizēti paskaidrots, kā izvietošanas laikā atrisināt datu bāzes saderības problēmas. Mēs jums pateiksim, kas var notikt ar jūsu ražošanas lietojumprogrammām, ja mēģināt izvietot bez iepriekšējas sagatavošanās. Pēc tam mēs iziesim cauri lietojumprogrammas dzīves cikla posmiem, kas ir nepieciešami, lai dīkstāve nebūtu nulles (apm. josla: tālāk - nulle dīkstāves). Mūsu darbību rezultāts būs ar atpakaļejošu datu nesaderīgu datu bāzes izmaiņu piemērošana atpakaļsaderīgā veidā.

Ja vēlaties saprast koda piemērus no raksta, varat tos atrast vietnē GitHub.

Ievads

Nulles dīkstāves izvietošana

Kas par mistisku nulles dīkstāves izvietošana? Var teikt, ka tas ir tad, kad jūsu lietojumprogramma tiek izvietota tā, ka varat veiksmīgi ieviest jaunu lietojumprogrammas versiju ražošanā, kamēr lietotājs nepamana tās nepieejamību. No lietotāja un uzņēmuma viedokļa šis ir labākais iespējamais izvietošanas scenārijs, jo tas ļauj bez traucējumiem ieviest jaunas funkcijas un novērst kļūdas.

Kā to panākt? Ir vairāki veidi, šeit ir viens no tiem:

  • izvietojiet sava pakalpojuma versiju Nr. 1
  • veikt datu bāzes migrāciju
  • Izvietojiet pakalpojuma 2. versiju paralēli versijai #1
  • tiklīdz redzat, ka versija Nr.2 darbojas kā nākas, noņemiet versiju Nr.1
  • ir gatavs!

Viegli, vai ne? Diemžēl tas nav tik vienkārši, un mēs to sīkāk aplūkosim vēlāk. Tagad pārbaudīsim vēl vienu diezgan izplatītu izvietošanas procesu - zili zaļo izvietošanu.

Vai esat kādreiz dzirdējuši zili zaļa izvietošana? Cloud Foundry to padara ārkārtīgi vienkāršu. Vienkārši paskaties šis raksts, kur mēs to aprakstām sīkāk. Īsi apkopojot, atgādināsim, kā veikt zili zaļo izvietošanu:

  • nodrošināt, ka darbojas divas jūsu ražošanas koda kopijas (“zilā” un “zaļā”);
  • novirzīt visu satiksmi uz zilo vidi, t.i. lai ražošanas vietrāži URL norādītu tur;
  • izvietot un pārbaudīt visas lietojumprogrammu izmaiņas zaļā vidē;
  • pārslēgt URL no zilas uz zaļu vidi

Zili zaļā izvietošana ir pieeja, kas ļauj viegli ieviest jaunas funkcijas, neuztraucoties par ražošanas pārtraukšanu. Tas ir saistīts ar faktu, ka pat tad, ja kaut kas notiek, varat viegli atgriezties iepriekšējā vidē, vienkārši "nospiežot slēdzi".

Izlasot visu iepriekš minēto, varat uzdot jautājumu: kāds sakars nulles dīkstāvei ar Blue Green izvietošanu?

Viņiem ir diezgan daudz kopīga, jo vienas vides divu kopiju uzturēšana prasa dubultas pūles, lai tās uzturētu. Tāpēc dažas komandas apgalvo Mārtiņš Faulers, izmantojiet šīs pieejas variantu:

Vēl viena iespēja ir izmantot to pašu datu bāzi, izveidojot zili zaļus slēdžus tīmekļa un domēna slāņiem. Izmantojot šo pieeju, datubāze bieži var radīt problēmas, it īpaši, ja ir jāmaina tās shēma, lai atbalstītu jaunu programmatūras versiju.

Un šeit mēs nonākam pie galvenās problēmas šajā rakstā. Datu bāze. Apskatīsim šo frāzi vēlreiz.

veikt datu bāzes migrāciju.

Tagad tev jāuzdod sev jautājums – ja nu datu bāzes maiņa nav atgriezeniski savietojama? Vai mana lietotnes pirmā versija nepārtrūks? Patiesībā tieši tā arī notiks...

Tātad, pat neskatoties uz milzīgajiem ieguvumiem no nulles dīkstāves / zili zaļās izvietošanas, uzņēmumi mēdz ievērot šādu drošāku procesu savu lietojumprogrammu izvietošanai:

  • sagatavot pakotni ar jaunu lietojumprogrammas versiju
  • izslēdziet darbojošos lietojumprogrammu
  • palaidiet skriptus datu bāzes migrēšanai
  • izvietojiet un palaidiet jaunu lietojumprogrammas versiju

Šajā rakstā mēs detalizēti aprakstīsim, kā varat strādāt ar savu datu bāzi un kodu, lai izmantotu nulles dīkstāves izvietošanas priekšrocības.

Datu bāzes problēmas

Ja jums ir bezvalsts lietojumprogramma, kas nesaglabā nekādus datus datu bāzē, varat uzreiz iegūt nulles dīkstāves izvietošanu. Diemžēl lielākajai daļai programmatūras kaut kur ir jāglabā dati. Tāpēc pirms jebkādu izmaiņu veikšanas ķēdē jums vajadzētu padomāt divreiz. Pirms iedziļināmies detaļās par to, kā mainīt shēmu, lai būtu iespējama izvietošana bez dīkstāves, vispirms pievērsīsimies versiju veidošanas shēmai.

Versiju shēma

Šajā rakstā mēs izmantosim Lidotais ceļš kā versiju kontroles rīks (apm. Tulkojums: mēs runājam par datu bāzu migrāciju). Protams, mēs uzrakstīsim arī Spring Boot lietojumprogrammu, kurai ir iebūvēts Flyway atbalsts un kas veiks shēmas migrāciju, iestatot lietojumprogrammas kontekstu. Izmantojot Flyway, varat saglabāt migrācijas skriptus projektu mapē (pēc noklusējuma mapē classpath:db/migration). Šeit jūs varat redzēt šādu migrācijas failu piemēru

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

Šajā piemērā mēs redzam 4 migrācijas skriptus, kas, ja tie nav izpildīti iepriekš, tiks izpildīti viens pēc otra, kad programma tiek startēta. Apskatīsim vienu no failiem (V1__init.sql) kā piemērs.

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

Viss ir pilnīgi pašsaprotami: jūs varat izmantot SQL, lai noteiktu, kā datu bāze ir jāmaina. Lai iegūtu papildinformāciju par Spring Boot un Flyway, skatiet Spring Boot Docs.

Izmantojot avota kontroles rīku ar Spring Boot, jūs iegūsit 2 lielas priekšrocības:

  • jūs atdala datu bāzes izmaiņas no koda izmaiņām
  • Datu bāzes migrācija notiek kopā ar jūsu lietojumprogrammas izlaišanu, t.i. jūsu izvietošanas process ir vienkāršots

Datu bāzes problēmu novēršana

Nākamajā raksta sadaļā mēs pievērsīsimies divām pieejām datu bāzes izmaiņām.

  • atpakaļejoša nesaderība
  • atpakaļejoša saderība

Pirmais tiks uzskatīts par brīdinājumu, ka bez iepriekšējas sagatavošanās nevajadzētu veikt nulles dīkstāves izvietošanu... Otrais piedāvā risinājumu, kā veikt izvietošanu bez dīkstāves un tajā pašā laikā saglabāt atpakaļejošu saderību.

Mūsu projekts, pie kura mēs strādāsim, būs vienkārša Spring Boot Flyway lietojumprogramma, kurai ir Person с first_name и last_name datu bāzē (apm. tulkojums: Person ir tabula un first_name и last_name - tie ir lauki tajā). Mēs vēlamies pārdēvēt last_name в surname.

Pieņēmumi

Pirms mēs iedziļināmies detaļās, mums ir jāizdara daži pieņēmumi par mūsu lietojumprogrammām. Galvenais rezultāts, ko vēlamies sasniegt, būs diezgan vienkāršs process.

Piezīme. Biznesa PRO-TIP. Procesu vienkāršošana var ietaupīt daudz naudas par atbalstu (jo vairāk cilvēku strādā jūsu uzņēmumā, jo vairāk naudas jūs varat ietaupīt)!

Nav nepieciešams atjaunot datubāzi

Tas vienkāršo izvietošanas procesu (dažu datu bāzes atcelšana ir gandrīz neiespējama, piemēram, dzēšanas atcelšana). Mēs dodam priekšroku tikai lietojumprogrammu atsaukšanai. Tādā veidā, pat ja jums ir dažādas datu bāzes (piemēram, SQL un NoSQL), jūsu izvietošanas konveijera izskats būs vienāds.

VIENMĒR jābūt iespējai atgriezt lietojumprogrammu par vienu versiju atpakaļ (ne vairāk)

Atcelšana jāveic tikai nepieciešamības gadījumā. Ja pašreizējā versijā ir kļūda, kuru nav viegli novērst, mums vajadzētu būt iespējai atgriezties pie jaunākās darba versijas. Mēs pieņemam, ka šī jaunākā darba versija ir iepriekšējā. Uzturēt kodu un datu bāzes saderību vairāk nekā vienai izlaišanai būtu ārkārtīgi sarežģīta un dārga.

Piezīme. Lai nodrošinātu labāku lasāmību, šajā rakstā mēs mainīsim lietojumprogrammas galveno versiju.

1. darbība. Sākotnējais stāvoklis

Lietotnes versija: 1.0.0
DB versija: v1

Komentēt

Tas būs lietojumprogrammas sākotnējais stāvoklis.

Datu bāzes izmaiņas

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

Koda izmaiņas

Lietojumprogramma saglabā personas datus 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
                + "]";
    }
}

Atpakaļ nesaderīga kolonnu pārdēvēšana

Apskatīsim piemēru, kā mainīt kolonnas nosaukumu:

Uzmanību. Šis piemērs apzināti sabojās lietas. Mēs to parādām, lai parādītu datu bāzes saderības problēmu.

Lietotnes versija: 2.0.0.BAD

DB versija: v2bad

Komentēt

Pašreizējās izmaiņas neļauj mums vienlaikus palaist divus gadījumus (veco un jauno). Tādējādi nulles dīkstāves izvietošanu būs grūti panākt (ja ņem vērā pieņēmumus, tas faktiski nav iespējams).

A/B testēšana

Pašreizējā situācija ir tāda, ka mums ir aplikācijas versija 1.0.0, izvietots ražošanā un datu bāzē v1. Mums ir jāizvieto otrais lietojumprogrammas gadījums, versija 2.0.0.BADun atjauniniet datu bāzi uz v2bad.

Soļi:

  1. tiek izvietots jauns versijas lietojumprogrammas gadījums 2.0.0.BADkas atjaunina datu bāzi uz v2bad
  2. datu bāzē v2bad sleja last_name vairs nepastāv — tas tika mainīts uz surname
  3. Datu bāzes un lietojumprogrammas atjaunināšana bija veiksmīga, un daži gadījumi darbojas 1.0.0, citi - iekšā 2.0.0.BAD. Viss ir savienots ar datu bāzi v2bad
  4. visi versijas gadījumi 1.0.0 sāks mest kļūdas, jo mēģinās ievietot datus kolonnā last_namekura vairs nepastāv
  5. visi versijas gadījumi 2.0.0.BAD darbosies bez problēmām

Kā redzat, ja mēs veicam atpakaļ nesaderīgas izmaiņas datu bāzē un lietojumprogrammā, A/B testēšana nav iespējama.

Lietojumprogrammas atcelšana

Pieņemsim, ka pēc mēģinājuma veikt A/B izvietošanu (apm. per.: autors te laikam domājis A/B testēšanu), mēs nolēmām, ka mums ir jāatgriež lietojumprogrammas versija 1.0.0. Pieņemsim, ka mēs nevēlamies atsaukt datubāzi.

Soļi:

  1. mēs pārtraucam versijas lietojumprogrammas gadījumu 2.0.0.BAD
  2. datubāze joprojām ir v2bad
  3. kopš versijas 1.0.0 nesaprot, kas tas ir surname, mēs redzēsim kļūdas
  4. elle ir atraisījusies, mēs vairs nevaram atgriezties

Kā redzat, ja mēs veicam atpakaļ nesaderīgas izmaiņas datu bāzē un lietojumprogrammā, mēs nevaram atgriezties pie iepriekšējās versijas.

Skriptu izpildes žurnāli

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 bāzes izmaiņas

Migrācijas skripts, kas pārdēvē last_name в surname

Avots Flyway skripts:

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

Skripts, kas pārdēvē last_name.

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

Koda izmaiņas

Mēs esam mainījuši lauka nosaukumu lastName par surname.

Kolonnas pārdēvēšana atpakaļ saderīgā veidā

Šī ir visizplatītākā situācija, ar kuru mēs varam saskarties. Mums ir jāveic atgriezeniski nesaderīgas izmaiņas. Mēs jau esam pierādījuši, ka izvietošanai bez dīkstāves mums nevajadzētu vienkārši piemērot datu bāzes migrāciju bez papildu darbībām. Šajā raksta sadaļā mēs veiksim 3 lietojumprogrammas izvietošanu kopā ar datu bāzes migrāciju, lai sasniegtu vēlamo rezultātu, vienlaikus saglabājot atpakaļejošu saderību.

Piezīme. Atcerieties, ka mums ir versiju datu bāze v1. Tajā ir kolonnas first_name и last_name. Mums ir jāmainās last_name par surname. Mums ir arī lietotnes versija 1.0.0, kas vēl netiek izmantots surname.

2. darbība: pievienojiet uzvārdu

Lietotnes versija: 2.0.0
DB versija: v2

Komentēt

Pievienojot jaunu kolonnu un kopējot tās saturu, mēs izveidojam atpakaļsaderīgas datu bāzes izmaiņas. Tajā pašā laikā, ja mēs atcelsim JAR vai palaižam vecu JAR, izpildes laikā tas nesaplīsīs.

Mēs izlaižam jaunu versiju

Soļi:

  1. veikt datu bāzes migrāciju, lai izveidotu jaunu kolonnu surname. Tagad jūsu DB versija v2
  2. kopēt datus no last_name в surname. Обратите вниманиеJa jums ir daudz šo datu, jums vajadzētu apsvērt pakešu migrāciju!
  3. ierakstiet kodu, kur tie tiek izmantoti ABI и jaunsUn vecais kolonna. Tagad jūsu lietotnes versija 2.0.0
  4. nolasīt vērtību no kolonnas surname, ja tā nav null, vai no last_name, ja surname nav precizēts. Jūs varat izdzēst getLastName() no koda, jo tas tiks izvadīts null atceļot pieteikumu no 3.0.0 līdz 2.0.0.

Ja izmantojat Spring Boot Flyway, šīs divas darbības tiks veiktas versijas startēšanas laikā 2.0.0 lietojumprogrammas. Ja palaižat datu bāzes versiju veidošanas rīku manuāli, jums būs jāveic divas dažādas darbības (vispirms manuāli jāatjaunina db versija un pēc tam jāizvieto jaunā lietojumprogramma).

Tas ir svarīgi. Atcerieties, ka jaunizveidotā kolonna NEVAJADZĒTU būt NAV NULL. Ja veicat atcelšanu, vecā lietojumprogramma nezina par jauno kolonnu un neinstalēs to laikā Insert. Bet, ja pievienosit šo ierobežojumu un jūsu db būs v2, būs jāiestata jaunās kolonnas vērtība. Kas novedīs pie ierobežojumu pārkāpumiem.

Tas ir svarīgi. Jums vajadzētu noņemt metodi getLastName(), jo versijā 3.0.0 Kodā nav kolonnas jēdziena last_name. Tas nozīmē, ka tur tiks iestatīts nulle. Varat atstāt metodi un pievienot čekus null, bet daudz labāks risinājums būtu pārliecināties par to loģikā getSurname() jūs atlasījāt pareizo vērtību, kas nav nulle.

A/B testēšana

Pašreizējā situācija ir tāda, ka mums ir aplikācijas versija 1.0.0, kas ir izvietots ražošanā, un datubāze v1. Mums ir jāizvieto versijas lietojumprogrammas otrais gadījums 2.0.0kas atjauninās datubāzi uz v2.

Soļi:

  1. tiek izvietots jauns versijas lietojumprogrammas gadījums 2.0.0kas atjaunina datu bāzi uz v2
  2. pa to laiku dažus pieprasījumus apstrādāja versiju gadījumi 1.0.0
  3. atjaunināšana bija veiksmīga, un jums ir vairākas versijas lietojumprogrammas darbības 1.0.0 un citas versijas 2.0.0. Ikviens sazinās ar datu bāzi v2
  4. versija 1.0.0 datubāzē neizmanto uzvārda aili, bet gan versiju 2.0.0 lietojumiem. Tie netraucē viens otram, un nevajadzētu būt kļūdām.
  5. versija 2.0.0 saglabā datus gan vecajā, gan jaunajā kolonnā, nodrošinot atpakaļejošu saderību

Tas ir svarīgi. Ja jums ir kādi vaicājumi, kas uzskaita vienumus, pamatojoties uz vērtībām no vecās/jaunās kolonnas, atcerieties, ka tagad jums ir dublētās vērtības (visticamāk, tās joprojām tiek migrētas). Piemēram, ja vēlaties saskaitīt to lietotāju skaitu, kuru uzvārds (neatkarīgi no tā, kā tiek saukta kolonna) sākās ar burtu A, pēc tam, līdz datu migrēšana ir pabeigta (oldnew kolonnā), iespējams, jums būs pretrunīgi dati, ja pieprasāt jaunu kolonnu.

Lietojumprogrammas atcelšana

Tagad mums ir lietotnes versija 2.0.0 un datu bāzē v2.

Soļi:

  1. atgrieziet lietojumprogrammas versiju 1.0.0.
  2. versija 1.0.0 neizmanto kolonnu datu bāzē surname, tāpēc atcelšanai vajadzētu būt veiksmīgai

DB izmaiņas

Datu bāzē ir kolonna ar nosaukumu last_name.

Flyway avota skripts:

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

Pievienojiet skriptu surname.

Uzmanību. Atcerieties, ka jūs NEVARAT PIEVIENOT nekādus NOT NULL ierobežojumus kolonnai, kuru pievienojat. Ja atcelsit JAR, vecajai versijai nebūs ne jausmas par pievienoto kolonnu, un tā automātiski iestatīs to uz NULL. Ja ir šāds ierobežojums, vecā lietojumprogramma vienkārši sabojāsies.

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

Koda izmaiņas

Mēs uzglabājam datus kā last_nameun iekšā surname. Tajā pašā laikā mēs lasām no last_name, jo šī sleja ir visatbilstošākā. Izvietošanas procesa laikā dažus pieprasījumus, iespējams, ir apstrādājusi lietojumprogrammas instance, kas vēl nav atjaunināta.

/*
 * 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. darbība: uzvārda noņemšana no koda

Lietotnes versija: 3.0.0

DB versija:v3

Komentēt

Piezīme per.: Acīmredzot sākotnējā rakstā autors kļūdaini nokopēja šī bloka tekstu no 2. darbības. Šajā solī ir jāveic izmaiņas lietojumprogrammas kodā, lai noņemtu funkcionalitāti, kas izmanto kolonnu. last_name.

Pievienojot jaunu kolonnu un kopējot tās saturu, mēs izveidojām atpakaļsaderīgas datu bāzes izmaiņas. Turklāt, ja mēs atcelsim JAR vai palaižam vecu JAR, izpildes laikā tas neplīst.

Lietojumprogrammas atcelšana

Pašlaik mums ir lietotnes versija 3.0.0 un datubāze v3. Versija 3.0.0 nesaglabā datus last_name. Tas nozīmē, ka iekš surname tiek saglabāta visjaunākā informācija.

Soļi:

  1. atgrieziet lietojumprogrammas versiju 2.0.0.
  2. versija 2.0.0 lieto un last_name и surname.
  3. versija 2.0.0 paņems surname, ja tā nav nulle, pretējā gadījumā -last_name

Datu bāzes izmaiņas

Strukturālu izmaiņu datubāzē nav. Lai veiktu veco datu galīgo migrāciju, tiek izpildīts šāds skripts:

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

Koda izmaiņas

Piezīme per.: Arī šī bloka aprakstu autors kļūdaini nokopēja no 2. darbības. Saskaņā ar raksta loģiku, šajā solī veiktajām izmaiņām kodā jābūt vērstām uz to, lai no tā tiktu noņemti elementi, kas darbojas ar kolonnu last_name.

Mēs uzglabājam datus kā last_nameun iekšā surname. Turklāt mēs lasām no slejas last_name, jo tas ir visatbilstošākais. Izvietošanas procesa laikā dažus pieprasījumus var apstrādāt instance, kas vēl nav jaunināta.

/*
 * 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. darbība. Last_name noņemšana no datu bāzes

Lietotnes versija: 4.0.0

DB versija: v4

Komentēt

Sakarā ar to, ka versijas kods 3.0.0 kolonnu neizmantoja last_name, izpildes laikā nekas slikts nenotiks, ja atgriezīsimies pie 3.0.0 pēc kolonnas noņemšanas no datu bāzes.

Skriptu izpildes žurnāli

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 izmaiņas

Salīdzinoši v3 mēs vienkārši noņemam kolonnu last_name un pievienojiet trūkstošos ierobežojumus.

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

Koda izmaiņas

Kodā nav izmaiņu.

secinājums

Mēs veiksmīgi veicām ar atpakaļejošu datu nesaderīgu kolonnas nosaukuma maiņu, veicot vairākas ar atpakaļejošas saderīgas izvietošanas. Tālāk ir sniegts veikto darbību kopsavilkums:

  1. lietojumprogrammas versijas izvietošana 1.0.0 с v1 datu bāzes shēma (kolonnas nosaukums = last_name)
  2. lietojumprogrammas versijas izvietošana 2.0.0, kurā tiek glabāti dati last_name и surname. Pieteikums skan no last_name. Datubāze ir versijā v2satur tādas kolonnas kā last_nameUn surname. surname ir kopija last_name. (PIEZĪME. Šajā kolonnā nedrīkst būt ierobežojumu, kas nav nulles)
  3. lietojumprogrammas versijas izvietošana 3.0.0, kurā tiek glabāti tikai dati surname un skan no uzvārda. Kas attiecas uz datubāzi, tad notiek pēdējā migrācija last_name в surname. Arī ierobežojums NAV NULL noņemts no last_name. Datubāze tagad ir versijā v3
  4. lietojumprogrammas versijas izvietošana 4.0.0 - kodā netiek veiktas nekādas izmaiņas. Datu bāzes izvietošana v4, kas noņem last_name. Šeit datu bāzei varat pievienot visus trūkstošos ierobežojumus.

Izmantojot šo pieeju, jūs vienmēr varat atsaukt vienu versiju, nepārkāpjot datu bāzes/lietojumprogrammu saderību.

Kods

Viss šajā rakstā izmantotais kods ir pieejams vietnē GitHub. Zemāk ir papildu apraksts.

Projekti

Pēc repozitorija klonēšanas jūs redzēsit šādu mapju struktūru.

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

Skripti

Varat palaist skriptus, kas aprakstīti tālāk esošajos skriptos, kas demonstrēs atpakaļsaderīgas un nesaderīgas izmaiņas datu bāzē.

Lai redzētu gadījumā ar atpakaļsaderīgām izmaiņām, palaist:

./scripts/scenario_backward_compatible.sh

Un redzēt gadījums ar atpakaļ nesaderīgām izmaiņām, palaist:

./scripts/scenario_backward_incompatible.sh

Pavasara zābaku parauga lidošanas ceļš

Visi piemēri ir ņemti no Spring Boot Sample Flyway.

Jūs varat apskatīt http://localhost:8080/flyway, ir skriptu saraksts.

Šajā piemērā ir iekļauta arī H2 konsole (at http://localhost:8080/h2-console), lai jūs varētu skatīt datu bāzes statusu (noklusējuma jdbc URL ir jdbc:h2:mem:testdb).

papildus

Lasiet arī citus rakstus mūsu emuārā:

Avots: www.habr.com

Pievieno komentāru