Zero stilstand ontplooiing en databasisse

Zero stilstand ontplooiing en databasisse

Hierdie artikel verduidelik in detail hoe om databasisversoenbaarheidskwessies tydens ontplooiing te hanteer. Ons sal jou vertel wat met jou toepassings op produksie kan gebeur as jy probeer ontplooi sonder vooraf voorbereiding. Ons sal dan deur die toepassing lewensiklusstappe loop wat vereis word om geen stilstand te hê nie (ongeveer. vertaal: verder - nul stilstand). Die resultaat van ons bedrywighede sal wees om 'n terugwaarts-onversoenbare databasisverandering op 'n terugwaarts-versoenbare wyse toe te pas.

As jy die kodevoorbeelde uit die artikel wil verstaan, kan jy dit vind by GitHub.

Inleiding

Geen stilstand-ontplooiing nie

Wat is mistiek nul stilstand ontplooiing? Jy kan sê dit is wanneer jou toepassing ontplooi word sodat jy 'n nuwe weergawe van die toepassing suksesvol in produksie kan bring sonder dat die gebruiker agterkom dat dit nie beskikbaar is nie. Vanuit 'n gebruiker- en maatskappy-oogpunt is dit die beste moontlike implementeringscenario, aangesien dit toelaat dat nuwe funksies bekendgestel word en foute reggestel kan word sonder ontwrigting.

Hoe om dit te bereik? Daar is verskeie maniere, hier is een van hulle:

  • ontplooi weergawe #1 van jou diens
  • doen 'n databasismigrasie
  • ontplooi weergawe #2 van u diens parallel met weergawe #1
  • sodra jy sien weergawe #2 werk soos dit moet, verwyder weergawe #1
  • gereed!

Maklik, is dit nie? Ongelukkig is dit nie so maklik nie, en ons sal later in detail daarna kyk. En kom ons kyk nou na nog 'n redelik algemene ontplooiingsproses - blougroen ontplooiing.

Het jy al ooit gehoor van blougroen ontplooiing? Met Cloud Foundry is dit uiters maklik om te doen. Kyk maar na hierdie artikelwaar ons dit in meer besonderhede beskryf. Kortliks opsomming, laat ons onthou hoe om blougroen ontplooiing te doen:

  • verskaf twee kopieë van jou produksiekode (“blou” en “groen”);
  • lei alle verkeer na die blou omgewing, d.w.s. sodat produksie-URL's daarheen wys;
  • ontplooi en toets alle toepassingsveranderinge in 'n groen omgewing;
  • skakel URL's van blou na groen omgewing

Blougroen-ontplooiing is 'n benadering wat jou toelaat om maklik nuwe kenmerke bekend te stel sonder om bekommerd te wees dat produksie sal breek. Dit is te wyte aan die feit dat selfs al gebeur iets, jy maklik kan terugrol na die vorige omgewing deur bloot 'n skakelaar te tik.

Nadat u al die bogenoemde gelees het, kan u uself afvra: Wat het nul stilstand met blougroen-ontplooiings te doen?

Wel, hulle het nogal baie in gemeen, aangesien die instandhouding van twee kopieë van dieselfde omgewing dubbel die moeite verg om hulle te onderhou. Dit is hoekom sommige opdragte, soos beweer Martin Fowler, volg 'n variasie van hierdie benadering:

'n ander opsie is om dieselfde databasis te gebruik, wat blougroen skakelaars vir die web- en domeinlae skep. Databasisse kan dikwels 'n probleem in hierdie benadering wees, veral wanneer jy hul skema moet verander om 'n nuwe weergawe van die sagteware te ondersteun.

En hier kom ons by die hoofprobleem in hierdie artikel. databasis. Kom ons kyk weer na hierdie frase.

voer 'n databasismigrasie uit.

Nou moet jy jouself die vraag afvra - wat as die verandering van die databasis terugwaarts onversoenbaar is? Sal my eerste weergawe van die toepassing nie breek nie? Trouens, dit is presies wat sal gebeur...

Dus, selfs met die groot voordele van geen stilstand / blougroen ontplooiing, is maatskappye geneig om die volgende veiliger ontplooiingsproses vir hul toepassings te volg:

  • berei 'n pakket met 'n nuwe weergawe van die toepassing voor
  • sluit lopende toepassing af
  • voer skrifte uit vir databasismigrasie
  • ontplooi en voer 'n nuwe weergawe van die toepassing uit

In hierdie artikel sal ons verduidelik hoe u met die databasis en kode kan werk om voordeel te trek uit 'n stilstand-ontplooiing.

Databasis kwessies

As jy 'n staatlose toepassing het wat geen data in die databasis stoor nie, kan jy dadelik geen stilstandtyd ontplooiing kry nie. Ongelukkig moet die meeste sagteware data iewers stoor. Dit is hoekom jy twee keer moet dink voordat jy enige veranderinge aan die stroombaan maak. Voordat ons ingaan op die besonderhede van hoe om die skema te verander sodat geen stilstand-ontplooiing moontlik is nie, laat ons eers fokus op die weergawebeheerskema.

Weergawebeheerskema

In hierdie artikel sal ons gebruik vliegpad as 'n weergawebeheerinstrument (ongeveer. per.: ons praat van databasismigrasies). Ons sal natuurlik ook 'n Spring Boot-toepassing skryf wat ingeboude ondersteuning vir Flyway het en skemamigrasie sal uitvoer tydens toepassingskonteksopstelling. Wanneer jy Flyway gebruik, kan jy migrasieskrifte in jou projekte-lêergids stoor (verstek in classpath:db/migration). Hier kan u 'n voorbeeld van sulke migrasielêers sien

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

In hierdie voorbeeld sien ons 4 migrasiescenario's wat, as hulle nie voorheen uitgevoer is nie, een na die ander uitgevoer sal word wanneer die toepassing begin. Kom ons kyk na een van die lêers (V1__init.sql) as 'n voorbeeld.

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

Alles spreek perfek vanself: jy kan SQL gebruik om te bepaal hoe jou databasis gewysig moet word. Vir meer inligting oor Spring Boot en Flyway, kyk na Spring Boot Docs.

Deur 'n weergawebeheerinstrument met Spring Boot te gebruik, kry jy 2 groot voordele:

  • jy skei databasis veranderinge van kode veranderinge
  • die databasismigrasie vind plaas saam met die ontplooiing van u toepassing, d.w.s. jou ontplooiingsproses is vereenvoudig

Los databasisprobleme op

In die volgende afdeling van die artikel sal ons fokus op twee benaderings tot databasisveranderinge.

  • terugwaartse onversoenbaarheid
  • terugwaartse verenigbaarheid

Die eerste een sal beskou word as 'n waarskuwing om nie 'n stilstand-ontplooiing te doen sonder vooraf voorbereiding nie... Die tweede een bied 'n oplossing vir hoe jy sonder stilstand kan ontplooi en terselfdertyd terugwaartse versoenbaarheid kan handhaaf.

Ons projek waaraan ons sal werk, sal 'n eenvoudige Spring Boot Flyway-toepassing wees wat het Person с first_name и last_name in die databasis (ongeveer. trans.: Person is 'n tafel en first_name и last_name is die velde daarin). Ons wil hernoem last_name в surname.

Aannames

Voordat ons in die besonderhede ingaan, moet ons 'n paar aannames maak oor ons toepassings. Die hoofresultaat wat ons wil bereik, sal 'n redelik eenvoudige proses wees.

Die nota. Besigheid PRO-WENK. Vereenvoudiging van prosesse kan jou baie geld spaar in ondersteuning (hoe meer mense jy het, hoe meer geld kan jy spaar)!

Geen databasisterugrol vereis nie

Dit vergemaklik die ontplooiingsproses (sommige databasisterugstellings is byna onmoontlik, soos terugrol van uitvee). Ons verkies om slegs toepassings terug te rol. Dus, selfs al het u verskillende databasisse (byvoorbeeld SQL en NoSQL), sal u ontplooiingspyplyn dieselfde lyk.

Dit is nodig dat dit ALTYD moontlik is om die toepassing een weergawe terug te rol (nie meer nie)

Terugdraai moet slegs gedoen word wanneer dit nodig is. As daar 'n fout in die huidige weergawe is wat nie maklik is om reg te stel nie, behoort ons na die nuutste werkende weergawe terug te kan terugkeer. Ons neem aan dat hierdie nuutste werkende weergawe die vorige een is. Die handhawing van kode- en databasisversoenbaarheid vir meer as een ontplooiing sal uiters moeilik en duur wees.

Die aantekening. Vir groter leesbaarheid sal ons in hierdie artikel die hoofweergawe van die toepassing verander.

Stap 1: Aanvanklike toestand

Programweergawe: 1.0.0
DB weergawe: v1

Lewer kommentaar

Dit sal die aanvanklike toestand van die aansoek wees.

Databasis veranderinge

DB bevat 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 verander

Die toepassing stoor Persoonsdata in 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
                + "]";
    }
}

Terugwaartse onversoenbare kolom hernoem

Kom ons kyk na 'n voorbeeld van hoe om die kolomnaam te verander:

Aandag. Die volgende voorbeeld sal doelbewus breek. Ons wys dit om die probleem van databasisversoenbaarheid te demonstreer.

Programweergawe: 2.0.0.BAD

DB weergawe: v2bad

Lewer kommentaar

Die huidige veranderinge laat ons NIE toe om twee instansies (oud en nuut) op dieselfde tyd te laat loop nie. Dus, nul stilstand-ontplooiing sal moeilik wees om te bereik (as jy die aannames in ag neem, is dit eintlik onmoontlik).

A/B-toetsing

Die huidige situasie is dat ons 'n weergawe-toepassing het 1.0.0, ontplooi in die verkoop, en die databasis v1. Ons moet 'n tweede instansie van die toepassing, weergawe, ontplooi 2.0.0.BAD, en werk die databasis op na v2bad.

stappe:

  1. het 'n nuwe weergawe-toepassingsinstansie ontplooi 2.0.0.BADwat die databasis opdateer na v2bad
  2. in die databasis v2bad kolom last_name bestaan ​​nie meer nie - dit is verander na surname
  3. die databasis en toepassing opgradering was suksesvol en sommige gevalle loop 1.0.0, ander in 2.0.0.BAD. Alles is DB verwant. v2bad
  4. alle gevalle van die weergawe 1.0.0 sal begin foute gooi omdat hulle sal probeer om data in die kolom in te voeg last_name, wat nie meer is nie
  5. alle gevalle van die weergawe 2.0.0.BAD sal sonder probleme werk

Soos u kan sien, as ons terugwaartse onversoenbare veranderinge aan die databasis en die toepassing maak, is A/B-toetsing nie moontlik nie.

Toepassing terugrol

Kom ons neem aan dat nadat ons probeer het om 'n A/B-ontplooiing te doen (ongeveer. per .: waarskynlik, hier het die skrywer A/B-toetsing bedoel) het ons besluit dat ons die toepassing na die weergawe moet terugrol 1.0.0. Kom ons sê ons wil nie die databasis terugrol nie.

stappe:

  1. ons stop die weergawe aansoek instansie 2.0.0.BAD
  2. die databasis is nog steeds v2bad
  3. sedert die weergawe 1.0.0 verstaan ​​nie wat is nie surname, sal ons foute sien
  4. hel het losgebars, ons kan nie meer teruggaan nie

Soos u kan sien, kan ons nie terugrol na die vorige weergawe as ons terugwaartse onversoenbare veranderinge aan die databasis en toepassing maak nie.

Skrip uitvoering logs

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

Databasis veranderinge

Migrasieskrif wat hernoem last_name в surname

Bron Flyway script:

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

Skrip wat hernoem last_name.

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

Kode verander

Ons het die naam van die veld verander lastName op surname.

Hernoem 'n kolom op 'n terugwaarts-versoenbare manier

Dit is die mees algemene situasie wat ons kan teëkom. Ons moet terugwaartse onversoenbare veranderinge maak. Ons het reeds bewys dat vir ontplooiing sonder stilstand, ons nie net 'n databasismigrasie moet toepas sonder bykomende stappe nie. In hierdie afdeling van die artikel sal ons 3-ontplooiings van die toepassing uitvoer saam met databasismigrasies om die gewenste resultaat te behaal terwyl terugwaartse versoenbaarheid behoue ​​bly.

Die nota. Onthou dat ons 'n weergawe DB het v1. Dit bevat kolomme first_name и last_name. Ons moet verander last_name op surname. Ons het ook app weergawe 1.0.0, wat nog nie gebruik word nie surname.

Stap 2: Voeg van by

Programweergawe: 2.0.0
DB weergawe: v2

Lewer kommentaar

Deur 'n nuwe kolom by te voeg en die inhoud daarvan te kopieer, skep ons terugwaarts-versoenbare databasisveranderinge. Terselfdertyd, as ons die JAR terugrol of 'n werkende ou JAR het, sal dit nie tydens looptyd breek nie.

Ontplooi 'n nuwe weergawe

stappe:

  1. doen 'n databasismigrasie om 'n nuwe kolom te skep surname. Nou jou db weergawe v2
  2. kopieer data van last_name в surname. Let weldat as jy baie van hierdie data het, jy bondelmigrasie moet oorweeg!
  3. skryf kode wat gebruik ALBEI и nuweEn die ou kolom. Nou jou toepassing weergawe 2.0.0
  4. lees waarde uit kolom surnameas dit nie is nie null, of van last_name, As 'n surname nie gestel nie. Jy kan uitvee getLastName() uit die kode soos dit sal uitreik null wanneer jy jou aansoek terugrol met 3.0.0 aan 2.0.0.

As jy Spring Boot Flyway gebruik, sal hierdie twee stappe tydens vrystelling gedoen word 2.0.0 toepassings. As jy die databasisweergawe-nutsding met die hand laat loop, sal jy twee verskillende stappe moet doen om dit te doen (gradeer eers die db-weergawe handmatig op en ontplooi dan die nuwe toepassing).

Belangrik. Onthou dat die nuutgeskepte kolom MOET NIE om te wees NIE NUL NIE. As jy 'n terugrol doen, weet die ou toepassing nie van die nuwe kolom nie en sal dit nie betyds stel nie Insert. Maar as jy hierdie beperking byvoeg en jou db sal wees v2, sal dit vereis dat die waarde van die nuwe kolom ingestel word. Wat sal lei tot beperkingsoortredings.

Belangrik. U moet die metode verwyder getLastName(), want in die weergawe 3.0.0 die konsep van 'n kolom ontbreek in die kode last_name. Dit beteken nul sal daar gestel word. Jy kan die metode verlaat en tjeks byvoeg vir null, maar 'n baie beter oplossing sou wees om seker te maak dat in die logika getSurname() jy het die korrekte nie-nulwaarde gekies.

A/B-toetsing

Die huidige situasie is dat ons 'n weergawe-toepassing het 1.0.0, ontplooi op die prod, en die databasis in v1. Ons moet 'n tweede instansie van die toepassingweergawe ontplooi 2.0.0wat die databasis sal opdateer na v2.

stappe:

  1. het 'n nuwe weergawe-toepassingsinstansie ontplooi 2.0.0wat die databasis opdateer na v2
  2. intussen is sommige versoeke deur weergawe-instansies hanteer 1.0.0
  3. die opgradering was suksesvol en jy het verskeie lopende gevalle van die weergawe-toepassing 1.0.0 en ander weergawes 2.0.0. Almal kommunikeer met die DB in v2
  4. weergawe 1.0.0 gebruik nie die vankolom in die databasis nie, maar die weergawe 2.0.0 gebruike. Hulle meng nie met mekaar in nie, en daar behoort geen foute te wees nie.
  5. weergawe 2.0.0 stoor data in beide die ou en nuwe kolom, wat terugwaartse versoenbaarheid verseker

Belangrik. As jy enige navrae het wat elemente tel gebaseer op waardes uit die ou/nuwe kolom, moet jy bewus wees dat jy nou duplikaatwaardes het (dit is heel waarskynlik steeds besig om te migreer). Byvoorbeeld, as jy die aantal gebruikers wil tel wie se van (wat ook al die naam van die kolom) met 'n letter begin A, dan totdat die data-migrasie voltooi is (oldnew kolom) jy kan dalk inkonsekwente data hê as jy 'n nuwe kolom navraag doen.

Toepassing terugrol

Ons het nou 'n toepassing weergawe 2.0.0 en databasis in v2.

stappe:

  1. rol jou toepassing terug na 'n weergawe 1.0.0.
  2. weergawe 1.0.0 gebruik nie 'n kolom in die databasis nie surnameso die terugrol behoort suksesvol te wees

DB veranderinge

Die databasis bevat 'n kolom met die naam last_name.

Flyway-bronskrif:

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

Voeg skrif by surname.

Aandag. Onthou dat jy GEEN NIE NULL-beperkings by die kolom wat bygevoeg word VOEG NIE. As jy die JAR terugrol, het die ou weergawe geen idee van die bygevoegde kolom nie en sal dit outomaties op NULL stel. As daar so 'n beperking is, sal die ou toepassing eenvoudig breek.

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

Ons stoor data as last_name, en in surname. Terselfdertyd lees ons uit last_namewant hierdie kolom is die mees relevante. Tydens die ontplooiingsproses is sommige versoeke moontlik verwerk deur 'n toepassingsinstansie wat nog nie opgedateer is nie.

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

Stap 3: Verwyder van naam van kode

Programweergawe: 3.0.0

DB weergawe:v3

Lewer kommentaar

Let wel. trans.: Blykbaar het die skrywer in die oorspronklike artikel verkeerdelik die teks van hierdie blok vanaf stap 2 gekopieer. By hierdie stap moet veranderinge aangebring word in die toepassingskode wat daarop gemik is om die funksionaliteit wat die kolom gebruik te verwyder last_name.

Deur 'n nuwe kolom by te voeg en die inhoud daarvan te kopieer, het ons terugwaarts versoenbare databasisveranderinge geskep. Ook, as ons die JAR terugrol of ons het 'n werkende ou JAR, sal dit nie tydens looptyd breek nie.

Toepassing terugrol

Ons het tans app weergawe 3.0.0 en databasis v3. Weergawe 3.0.0 stoor nie data in nie last_name. Dit beteken dat in surname die mees onlangse inligting word gestoor.

stappe:

  1. rol jou toepassing terug na 'n weergawe 2.0.0.
  2. weergawe 2.0.0 gebruik en last_name и surname.
  3. weergawe 2.0.0 sal neem surnameas dit nie nul is nie, anderslast_name

Databasis veranderinge

Daar is geen strukturele veranderinge in die databasis nie. Die volgende skrip word uitgevoer, wat die finale migrasie van die ou data uitvoer:

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

Let wel. per.: Die beskrywing van hierdie blok is ook verkeerdelik deur die skrywer gekopieer vanaf stap 2. In ooreenstemming met die logika van die artikel se vertelling, moet veranderinge in die kode by hierdie stap daarop gemik wees om elemente wat met die kolom werk, daaruit te verwyder last_name.

Ons stoor data as last_name, en in surname. Ook lees ons uit die rubriek last_namewant dit is die mees relevante. Tydens die ontplooiingsproses kan sommige versoeke verwerk word deur 'n instansie wat nog nie opgegradeer is nie.

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

Stap 4: Verwyder laaste_naam uit die databasis

Programweergawe: 4.0.0

DB weergawe: v4

Lewer kommentaar

Omdat die weergawe kode 3.0.0 het nie kolom gebruik nie last_name, niks sleg sal gebeur tydens uitvoering as ons terugrol na 3.0.0 na die verwydering van 'n kolom uit die databasis.

Skrip uitvoering logs

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 veranderinge

oor v3 ons verwyder net die kolom last_name en voeg die ontbrekende beperkings by.

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

Daar is geen veranderinge in die kode nie.

Output

Ons het die terugwaarts-onversoenbare kolomnaamverandering suksesvol toegepas deur verskeie terugwaartsversoenbare ontplooiings te doen. Hieronder is 'n opsomming van die stappe wat geneem is:

  1. app weergawe ontplooi 1.0.0 с v1 DB-skema (kolomnaam = last_name)
  2. app weergawe ontplooi 2.0.0, wat data stoor in last_name и surname. Die aansoek lees uit last_name. DB is in weergawe v2, wat kolomme soos last_nameEn surname. surname is 'n afskrif van last_name. (LET WEL: hierdie kolom moet nie 'n nie-nul-beperking hê nie)
  3. app weergawe ontplooi 3.0.0, wat slegs data stoor in surname en lees uit van. Wat die DB betref, vind die laaste migrasie plaas last_name в surname. Ook die beperking NIE NUL NIE onttrek aan last_name. DB is tans in weergawe v3
  4. app weergawe ontplooi 4.0.0 - geen veranderinge word aan die kode gemaak nie. Databasis ontplooiing v4, wat verwyder last_name. Hier kan jy enige ontbrekende beperkings by die databasis voeg.

Deur hierdie benadering te volg, kan jy altyd een weergawe terugrol sonder om databasis-/toepassingsversoenbaarheid te breek.

Kode

Alle kodes wat in hierdie artikel gebruik word, is beskikbaar by GitHub. Hieronder is 'n bykomende beskrywing.

Projekte

Nadat u die bewaarplek gekloon het, sal u die volgende gidsstruktuur sien.

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

Skrifte

Jy kan die skrifte wat in die skrifte hieronder beskryf word, laat loop, wat terugwaartsversoenbare en onversoenbare veranderinge aan die databasis sal demonstreer.

Om te sien geval met terugwaarts versoenbare veranderinge, hardloop:

./scripts/scenario_backward_compatible.sh

En om te sien geval van terugwaartse onversoenbare veranderinge, hardloop:

./scripts/scenario_backward_incompatible.sh

Spring Boot Voorbeeld Flyway

Alle voorbeelde is geneem uit Spring Boot Sample Flyway.

Jy kan kyk na http://localhost:8080/flyway, daar is 'n lys van skrifte.

Hierdie voorbeeld sluit ook die H2-konsole in (by http://localhost:8080/h2-console) sodat jy die toestand van die databasis kan sien (die verstek jdbc URL is jdbc:h2:mem:testdb).

Daarbenewens

Lees ook ander artikels op ons blog:

Bron: will.com

Voeg 'n opmerking