Zero Downtime Deployment û Databases

Zero Downtime Deployment û Databases

Vê gotarê bi hûrgulî rave dike ka meriv çawa pirsgirêkên lihevhatina databasê di bicîhkirinê de çareser dike. Em ê ji we re vebêjin ka çi dikare bi serîlêdanên hilberîna we re bibe heke hûn hewl bidin ku bêyî amadekariyek pêşîn bicîh bikin. Dûv re em ê di qonaxên çerxa jiyanê ya serîlêdanê re derbas bibin ku hewce ne ku demdirêjiya sifir hebe (approx. lane: bêtir - zero domdariya). Encama operasyonên me dê ev be ku em guheztina databasa nelihevkirî ya paşverû bi rengek lihevhatî bi paş ve bicîh bikin.

Heke hûn dixwazin mînakên kodê ji gotarê fêm bikin, hûn dikarin wan li wan bibînin GitHub.

Pîrozbahiyê

Zero bicîkirina downtime

Çi mîstîk e sifir bicihkirina downtime? Hûn dikarin bibêjin ev gava ku serîlêdana we bi vî rengî tête bicîh kirin ku hûn dikarin guhertoyek nû ya serîlêdanê bi serfirazî bi hilberînê bidin nasîn, di heman demê de ku bikarhêner haya wî ji tunebûna wê çênabe. Ji perspektîfa bikarhêner û pargîdaniyê, ev senaryoya sazkirinê ya çêtirîn gengaz e ji ber ku ew dihêle ku taybetmendiyên nû werin destnîşan kirin û xeletî bêyî astengî werin sererast kirin.

Çawa meriv vê yekê bi dest bixe? Gelek rê hene, li vir yek ji wan e:

  • guhertoya No. 1 ya karûbarê we bicîh bikin
  • koçek databasê pêk bînin
  • Guhertoya #2 ya karûbarê xwe bi guhertoya #1 re paralel bicîh bikin
  • gava ku hûn dibînin ku guhertoya No. 2 wekî ku divê dixebite, guhertoya No
  • amade ye!

Hêsan e, ne wisa? Mixabin, ew ne ew çend hêsan e, û em ê paşê bi berfirehî li ser wê binêrin. Naha em werin pêvajoyek din a danûstendinê ya pir hevpar kontrol bikin - bicîhkirina kesk şîn.

Ma we qet bihîstiye bicihkirina kesk şîn? Cloud Foundry vê yekê pir hêsan dike. Tenê lê binêrin vê gotarê, ku em vê yekê bi hûrgulî rave dikin. Ji bo ku bi kurtî kurt bikin, em bînin bîra we ka meriv çawa bicîhkirina kesk şîn dike:

  • piştrast bikin ku du kopiyên koda hilberîna we ("şîn" û "kesk") dixebitin;
  • rasterast hemû trafîkê ber bi jîngeha şîn, ango. da ku URLên hilberînê li wir destnîşan bikin;
  • hemî guhertinên serîlêdanê di hawîrdorek kesk de bicîh bikin û ceribandin;
  • urls ji hawîrdora şîn veguherînin kesk

Bicihkirina kesk şîn nêzîkatiyek e ku dihêle hûn bi hêsanî taybetmendiyên nû destnîşan bikin bêyî ku hûn ji şikandina hilberînê xeman bikin. Ev ji ber vê yekê ye ku her çend tiştek biqewime jî, hûn dikarin bi hêsanî bi "lêxistina guhezek" vegere hawîrdora berê.

Piştî xwendina hemî jorîn, hûn dikarin vê pirsê bipirsin: Çi pêwendiya zewaca zewacê bi bicîhkirina kesk Blue re heye?

Welê, ew pir pir hevpar in, ji ber ku domandina du kopiyên heman hawîrdorê ji bo domandina wan hewildana ducar hewce dike. Ji ber vê yekê hin tîm îdîa dikin Martin Fowler, guhertoyek vê rêbazê bişopînin:

Vebijarkek din ev e ku meriv heman databasê bikar bîne, ji bo qatên tevn û domainê guhezên şîn-kesk biafirîne. Di vê nêzîkbûnê de, databas pir caran dibe pirsgirêkek, nemaze dema ku hûn hewce ne ku şemaya wê biguhezînin da ku guhertoyek nû ya nermalavê piştgirî bike.

Û li vir em di vê gotarê de têne ser pirsgirêka sereke. Database. Ka em careke din li vê hevokê binêrin.

koçek databasê pêk bînin.

Naha divê hûn vê pirsê ji xwe bipirsin - heke guhertina databasê ne lihevhatî be, çi dibe? Ma dê guhertoya min a yekem a sepanê têk nebe? Bi rastî, ev e ku ew ê bibe…

Ji ber vê yekê, tewra digel feydeyên mezin ên zexmkirina sifir / bicîhkirina kesk şîn, pargîdanî ji bo bicîhkirina serîlêdanên xwe pêvajoya ewledar a jêrîn bişopînin:

  • bi guhertoyek nû ya serîlêdanê pakêtek amade bike
  • serîlêdanek xebitandinê biqedîne
  • ji bo koçkirina databasê nivîsan bimeşînin
  • guhertoyek nû ya serîlêdanê bicîh bikin û bidin destpêkirin

Di vê gotarê de, em ê hûrgulî bikin ka hûn çawa dikarin bi databas û koda xwe re bixebitin da ku sûd ji bicîhkirina dema domandinê ya sifir bigirin.

Pirsgirêkên Database

Ger we serîlêdanek bêdewlet heye ku tu daneyan di databasê de hilnagire, hûn dikarin tavilê dorvegera zewacê bistînin. Mixabin, pir nermalava pêdivî ye ku daneyan li cîhek hilîne. Ji ber vê yekê divê hûn du caran bifikirin berî ku hûn guhartinan di çerçoveyê de bikin. Berî ku em têkevin hûrguliyên ka meriv çawa şemayê biguhezîne da ku bicîhkirina bê-demê mumkun be, em pêşî li ser şema guhertoyê bisekinin.

Plana versiyonê

Di vê gotarê de em ê bikar bînin Flyway wekî amûrek kontrolkirina guhertoyê (approx. Werger: em behsa koçên databasê dikin). Bi xwezayî, em ê di heman demê de serîlêdanek Spring Boot-ê ya ku xwedan piştevaniya Flyway-yê çêkirî ye jî binivîsin û dema ku çarçoweya serîlêdanê saz dike dê koça şemayê pêk bîne. Dema ku Flyway bikar tînin, hûn dikarin skrîptên koçberiyê di peldanka projeyên xwe de hilînin (bi xwerû tê de classpath:db/migration). Li vir hûn dikarin mînakek pelên koçberiyê yên weha bibînin

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

Di vê nimûneyê de em 4 skrîptên koçberiyê dibînin ku, heke berê neyên darve kirin, gava ku serîlêdanê dest pê dike dê yek li dû hev bêne darve kirin. Ka em li yek ji pelan binêrin (V1__init.sql) wek nimûne.

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

Her tişt bêkêmasî xwe-ravekirî ye: hûn dikarin SQL bikar bînin da ku diyar bikin ka databasa we çawa were guheztin. Ji bo bêtir agahdarî di derbarê Spring Boot û Flyway de, binihêrin Bihara Boot Docs.

Bi karanîna amûrek kontrolê ya çavkaniyê bi Spring Boot re, hûn 2 feydeyên mezin digirin:

  • hûn guhertinên databasê ji guhertinên kodê veqetînin
  • Koçberiya databasê digel derxistina serîlêdana we pêk tê, ango. pêvajoya bicihkirina we hêsan e

Çareserkirina pirsgirêkên databasê

Di beşa paşîn a gotarê de, em ê li ser du nêzîkatiyên guhertinên databasê bisekinin.

  • lihevnebûna paşverû
  • lihevhatina paşverû

Ya yekem dê wekî hişyariyek were hesibandin ku divê hûn bêyî amadekariyek pêşwext nekêşana sifirê nexebitînin... Ya duyemîn çareseriyek pêşkêşî dike ku hûn çawa dikarin bêdemek dakêşanê pêk bînin û di heman demê de lihevhatina paşverû biparêzin.

Projeya me ya ku em ê li ser bixebitin dê serîlêdanek hêsan Spring Boot Flyway be ku heye Person с first_name и last_name di databasê de (approx. werger: Person tabloyek e û first_name и last_name - ev zeviyên tê de ne). Em dixwazin navê xwe biguherînin last_name в surname.

Pêşbîniyên

Berî ku em têkevin hûrguliyan, çend texmîn hene ku divê em li ser serîlêdanên xwe bikin. Encama sereke ya ku em dixwazin bi dest bixin dê pêvajoyek pir hêsan be.

The note. Business PRO-TIP. Pêvajoyên hêsan dikarin ji we re gelek drav li ser piştgirîyê xilas bikin (çiqas mirovên ku hûn ji bo pargîdaniya we dixebitin, ew qas bêtir drav hûn dikarin xilas bikin)!

Ne hewce ye ku databasê paşde vegerîne

Ev pêvajoya bicihkirinê hêsan dike (hin vegerandinên databasê hema hema ne mumkin in, wek paşvexistina jêbirinê). Em tercîh dikin ku tenê serlêdanan paşde vegerînin. Bi vî rengî, tewra ku we databasên cihêreng hebin (mînak, SQL û NoSQL), dê lûleya weya bicîhkirina we heman xuya bike.

Divê HER DEM gengaz be ku serîlêdanê yek guhertoyek paşde vegerîne (bêtir)

Divê vegerandin tenê gava ku hewce be were kirin. Ger di guhertoya heyî de xeletiyek hebe ku bi hêsanî nayê rast kirin, divê em karibin vegerin guhertoya xebatê ya herî dawî. Em texmîn dikin ku ev guhertoya xebatê ya herî dawî ya berê ye. Parastina lihevhatina kod û databasê ji bo zêdetirî yek pêvekirinê dê pir dijwar û biha be.

Nota. Ji bo xwendina mezintir, di vê gotarê de em ê guhertoya sereke ya serîlêdanê biguherînin.

Gav 1: Dewleta Destpêkê

Guhertoya sepanê: 1.0.0
Guhertoya DB: v1

Rayi

Ev dê bibe rewşa destpêkê ya serîlêdanê.

Guhertinên Database

DB dihewîne 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');

Kod diguhere

Serlêdan daneyên Kesane tê de hilîne 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
                + "]";
    }
}

Veguheztina navên stûnê bi paş ve

Ka em li mînakek binêrin ka meriv çawa navek stûnek biguhezîne:

Baldarî. Mînaka jêrîn dê bi mebest tiştan bişkîne. Em vê yekê destnîşan dikin ku pirsgirêka lihevhatina databasê nîşan bidin.

Guhertoya sepanê: 2.0.0.BAD

Guhertoya DB: v2bad

Rayi

Guhertinên heyî rê nadin me ku em du mînakan (kevn û nû) di heman demê de bimeşînin. Bi vî rengî, bicihkirina zewaca zexm dê dijwar be (heke texmîn bêne hesibandin, ew bi rastî ne gengaz e).

testkirina A/B

Rewşa heyî ev e ku guhertoyek me ya serîlêdanê heye 1.0.0, di hilberînê de, û databasê de têne bicîh kirin v1. Pêdivî ye ku em mînakek duyemîn a serîlêdanê, guhertoyek bicîh bikin 2.0.0.BAD, û databasê nûve bikin v2bad.

Steps:

  1. mînakek nû ya serîlêdana guhertoyê tê bicîh kirin 2.0.0.BADku databasê nûve dike v2bad
  2. di danegehê de v2bad ling last_name êdî tune - ew hate guherandin surname
  3. Database û nûvekirina serîlêdanê serketî bû û hin mînak têne xebitandin 1.0.0, yên din - in 2.0.0.BAD. Her tişt bi databasê ve girêdayî ye v2bad
  4. hemû mînakên guhertoyê 1.0.0 dê dest bi avêtina xeletiyan bikin ji ber ku ew ê hewl bidin ku daneyan têxin stûnê last_nameku êdî nemaye
  5. hemû mînakên guhertoyê 2.0.0.BAD dê bê pirsgirêk kar bikin

Wekî ku hûn dikarin bibînin, heke em li ser databas û serîlêdanê guhertinên lihevhatî yên paşverû bikin, ceribandina A/B ne mumkun e.

Vegera serîlêdanê

Ka em texmîn bikin ku piştî ku hewl didin ku bicîhkirina A/B bikin (approx. per.: belkî mebesta nivîskar li vir ceribandina A/B bû) me biryar da ku pêdivî ye ku em serîlêdanê vegerînin guhertoyê 1.0.0. Ka em bêjin em naxwazin databasê paşde vegerînin.

Steps:

  1. em mînaka serîlêdana guhertoyê rawestînin 2.0.0.BAD
  2. databas hîna ye v2bad
  3. ji ber ku guhertoya 1.0.0 fêm nake ka ew çi ye surname, em ê xeletiyan bibînin
  4. dojeh şikestiye, êdî em nikarin vegerin

Wekî ku hûn dikarin bibînin, heke em li ser databas û serîlêdanê guhertinên lihevnehatî bi paş ve bikin, em nikanin vegerin guhertoya berê.

Têketinên pêkanîna skrîptê

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

Guhertinên Database

Skrîpta koçberiyê ku navên xwe vediguherîne last_name в surname

Nivîsara Flyway çavkaniyê:

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

Skrîpta ku navê xwe vediguherîne last_name.

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

Kod diguhere

Me navê zeviyê guhert lastName li ser surname.

Guherîna navek stûnek bi rengek paşverû-lihevhatî

Ev rewşa herî gelemperî ye ku em pê re rû bi rû ne. Pêdivî ye ku em guhertinên paşverû yên lihevhatî bikin. Me jixwe îsbat kiriye ku ji bo bicihkirina zero-downtime, divê em ne tenê bêyî gavên pêvek koçkirina databasê bicîh bînin. Di vê beşa gotarê de, em ê 3 bicîhkirina serîlêdanê ligel koçên databasê pêk bînin da ku di heman demê de lihevhatina paşdemayî bigihîjin encama xwestinê.

The note. Bînin bîra xwe ku me databasek guhertoyek heye v1. Ew stûnan dihewîne first_name и last_name. Divê em biguherin last_name li ser surname. Versiyonek appê ya me jî heye 1.0.0, ya ku hê nehatiye bikaranîn surname.

Gav 2: Paşnav lê zêde bike

Guhertoya sepanê: 2.0.0
Guhertoya DB: v2

Rayi

Bi lêzêdekirina stûnek nû û kopîkirina naveroka wê, em guheztinên databasê yên lihevhatî paşverû diafirînin. Di heman demê de, heke em JAR-ê paşde vegerînin an JARek kevn hebe, ew ê di dema darvekirinê de neşike.

Em guhertoyek nû derdixin

Steps:

  1. koçek databasê pêk bînin da ku stûnek nû biafirînin surname. Naha guhertoya weya DB v2
  2. daneyên kopî ji last_name в surname. Bawer bikinku heke we gelek ji van daneyan hebin, divê hûn koçberiya hevîrê bifikirin!
  3. koda ku ew lê têne bikar anîn binivîse HERDÛ и новыйû kevn ling. Naha guhertoya sepana we 2.0.0
  4. nirxê ji stûnê bixwînin surname, heke ew nebe null, an ji last_name, heke surname ne diyar kirin. Hûn dikarin jêbirin getLastName() ji kodê, ji ber ku ew ê derkeve null dema ku serîlêdana xwe ji paş vedigerîne 3.0.0 ber 2.0.0.

Heke hûn Spring Boot Flyway bikar tînin, dê van her du gav di dema destpêkirina guhertoyê de bêne kirin 2.0.0 sepanên. Heke hûn amûra guhertoya databasê bi destan dimeşînin, divê hûn du tiştên cûda bikin ku vê yekê bikin (pêşîn guhertoya db-ê bi destan nûve bikin û dûv re serîlêdana nû bicîh bikin).

Ew girîng e. Bînin bîra xwe ku stûna nû hatî afirandin DIVÊ NEBE bibe NEDE. Ger hûn vegerek bikin, serîlêdana kevn ji stûna nû nizane û dê di dema wê de saz neke Insert. Lê heger hûn vê astengiyê zêde bikin û db dê bibe v2, ev ê hewce bike ku nirxa stûna nû were danîn. Ya ku dê bibe sedema binpêkirina qedexeyan.

Ew girîng e. Divê hûn rêbazê jêbirin getLastName(), ji ber ku di versiyonê de 3.0.0 Di kodê de têgîna stûnê tune last_name. Ev tê wê wateyê ku null dê li wir were danîn. Hûn dikarin rêbazê bihêlin û ji bo kontrolan zêde bikin null, lê çareseriyek pir çêtir dê ev be ku meriv di mantiqê de piştrast bike getSurname() te nirxa ne-sifir rast hilbijart.

testkirina A/B

Rewşa heyî ev e ku guhertoyek me ya serîlêdanê heye 1.0.0, li ser hilberînê, û databasa tê de hatî bicîh kirin v1. Pêdivî ye ku em mînakek duyemîn a serîlêdana guhertoyê bicîh bikin 2.0.0ku dê databasê nûve bike v2.

Steps:

  1. mînakek nû ya serîlêdana guhertoyê tê bicîh kirin 2.0.0ku databasê nûve dike v2
  2. di vê navberê de hin daxwaz ji hêla mînakên guhertoyê ve hatin pêvajo kirin 1.0.0
  3. nûvekirin serketî bû û we gelek mînakên xebitandinê yên serîlêdana guhertoyê hene 1.0.0 û versiyonên din 2.0.0. Her kes bi databasê re di têkiliyê de ye v2
  4. versiyon 1.0.0 di databasê de ne stûna paşnavê, lê guhertoyê bikar tîne 2.0.0 bikar tîne. Destwerdana hevdu nakin, divê xeletî jî tunebin.
  5. versiyon 2.0.0 daneyan hem di stûna kevn û hem jî ya nû de hilîne, lihevhatina paşverû misoger dike

Ew girîng e. Ger pirsên we hebin ku tiştan li ser bingeha nirxên ji stûna kevn/nû dihejmêrin, divê hûn ji bîr mekin ku we nuha nirxên dubare hene (bi îhtîmalek mezin ew hîn jî koç dikin). Mînakî, heke hûn dixwazin hejmara bikarhênerên ku paşnavê wan (çi ku jê re tê gotin stûnê) bi tîpê dest pê kiriye bijmêre. A, paşê heta ku koçkirina daneyan qediya (oldnew stûn) heke hûn li stûnek nû bipirsin dibe ku daneyên we nehevgirtî bin.

Vegera serîlêdanê

Naha me guhertoya sepanê heye 2.0.0 û databas tê de v2.

Steps:

  1. serîlêdana xwe vegerîne guhertoyê 1.0.0.
  2. versiyon 1.0.0 di databasê de stûnek bikar nayîne surname, ji ber vê yekê divê vegerandin serketî be

DB guhertin

Database stûnek bi navê heye last_name.

Nivîsara çavkaniya Flyway:

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

Skrîptê zêde bikin surname.

Baldarî. Bînin bîra xwe ku hûn NIKARIN ti astengiyên NE BELE li stûna ku hûn lê zêde dikin lê zêde bikin. Ger hûn JAR-ê paşde vegerînin, guhertoya kevn dê di derheqê stûna lêzêdekirî de nizane û bixweber wê li NULL-ê saz bike. Ger sînorkirinek wusa hebe, serîlêdana kevn dê bi tenê bişkîne.

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

Kod diguhere

Em daneyan wekî hundur hilînin last_nameû di surname. Di heman demê de em ji xwendin last_name, ji ber ku ev stûna herî têkildar e. Di dema pêvajoya bicîhkirinê de, dibe ku hin daxwaz ji hêla mînakek serîlêdanê ya ku hîn nehatiye nûve kirin ve hatî pêvajoyê kirin.

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

Gav 3: Rakirina paşnavê ji kodê

Guhertoya sepanê: 3.0.0

Guhertoya DB:v3

Rayi

Not per.: Xuya ye, di gotara orîjînal de nivîskar bi xeletî nivîsa vê blokê ji gava 2-an kopî kiriye. Di vê gavê de, divê di koda serîlêdanê de guheztin werin kirin ku armanca wê rakirina fonksiyona ku stûnê bikar tîne. last_name.

Bi lêzêdekirina stûnek nû û kopîkirina naveroka wê, me guheztinên databasa lihevhatî ya paşverû çêkir. Di heman demê de, heke em JAR-ê paşde vegerînin an JARek kevn hebe, ew ê di dema darvekirinê de neşike.

Vegera serîlêdanê

Niha guhertoya sepanê ya me heye 3.0.0 û database v3. Awa 3.0.0 daneyan tomar nake last_name. Ev tê wê wateyê ku di surname agahdariya herî nûjen tê hilanîn.

Steps:

  1. serîlêdana xwe vegerîne guhertoyê 2.0.0.
  2. versiyon 2.0.0 bi kar tîne û last_name и surname.
  3. versiyon 2.0.0 dê bigirin surname, heke ew ne sifir be, wekî din -last_name

Guhertinên Database

Di databasê de guhertinên strukturel tune. Skrîpta jêrîn tête darve kirin da ku koça dawî ya daneyên kevn pêk bîne:

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

Kod diguhere

Not per.: Danasîna vê blokê jî bi xeletî ji hêla nivîskar ve ji gava 2-an ve hatî kopî kirin. Li gorî mantiqa gotarê, guhertinên di kodê de di vê gavê de divê bi mebesta jêbirina hêmanên ku bi stûnê re dixebitin ji wê werin derxistin. last_name.

Em daneyan wekî tomar dikin last_nameû di surname. Wekî din, em ji stûnê dixwînin last_name, ji ber ku ew ya herî têkildar e. Di dema pêvajoya bicîhkirinê de, dibe ku hin daxwaz ji hêla mînakek ku hîn nehatiye nûve kirin ve bêne pêvajoyê kirin.

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

Gav 4: Rakirina paşnavê ji databasê

Guhertoya sepanê: 4.0.0

Guhertoya DB: v4

Rayi

Ji ber rastiya ku koda versiyonê 3.0.0 stûn bi kar neanîn last_name, di dema darvekirinê de tiştek xirab dê çênebe heke em vegerin 3.0.0 piştî rakirina stûnek ji databasê.

Têketinên pêkanîna skrîptê

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 guhertin

Nisba peywende v3 em tenê stûnê jê dikin last_name û qedexeyên wenda zêde bikin.

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

Kod diguhere

Di kodê de guhertin tune.

encamê

Me bi serketî guheztina navê stûnê ya paşverû-ne lihevhatî bi cîbicîkirina çend pêkanînên lihevhatî bi paş ve sepand. Li jêr kurteya çalakiyên ku hatine kirin hene:

  1. belavkirina guhertoya serîlêdanê 1.0.0 с v1 şema databasê (navê stûnê = last_name)
  2. belavkirina guhertoya serîlêdanê 2.0.0, ku daneyan tê de hilîne last_name и surname. Serlêdan ji dixwîne last_name. Database di versiyonê de ye v2stûnên mîna last_name, û surname. surname nusxeyek l yeast_name. (BALKÊŞÎ: Divê ev stûn ne xwedî astengiyek ne betal be)
  3. belavkirina guhertoya serîlêdanê 3.0.0, ku tenê daneyan tê de hilîne surname û ji paşnav dixwîne. Ji bo databasê, koça dawîn pêk tê last_name в surname. Her weha sînorek NEDE jê derxistin last_name. Database niha di versiyonê de ye v3
  4. belavkirina guhertoya serîlêdanê 4.0.0 - tu guhertin di kodê de nayê kirin. Daxistina Database v4, ku jê dike last_name. Li vir hûn dikarin her astengiyên wenda li databasê zêde bikin.

Bi şopandina vê nêzîkatiyê, hûn dikarin her gav yek guhertoyek paşde bavêjin bêyî ku lihevhatina databas / serîlêdanê bişkînin.

code

Hemî kodên ku di vê gotarê de têne bikar anîn li vir hene Github. Li jêr danasîna zêde heye.

Projeyên

Piştî klonkirina depoyê, hûn ê avahiya peldanka jêrîn bibînin.

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

Lîsans

Hûn dikarin nivîsarên ku di skrîptên jêrîn de hatine diyar kirin bimeşînin, ku dê guhartinên paşverû û nehevgirtî yên databasê nîşan bidin.

We helavê kur heye doza bi paş ve lihevhatî guhertin, rêve:

./scripts/scenario_backward_compatible.sh

Û bibînin doza bi paş de guhertinên ne lihevhatî, rêve:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Hemî mînak ji wan hatine girtin Spring Boot Sample Flyway.

Hûn dikarin lê binêrin http://localhost:8080/flyway, lîsteyek senaryoyan heye.

Di vê nimûneyê de konsolê H2 jî heye (li http://localhost:8080/h2-console) ji ber vê yekê hûn dikarin statûya databasê bibînin (URL-ya jdbc ya xwerû ye jdbc:h2:mem:testdb).

herweha

Her weha gotarên din ên li ser bloga me bixwînin:

Source: www.habr.com

Add a comment