Nol Downtime Deployment na basis data

Nol Downtime Deployment na basis data

Tulisan ieu ngajelaskeun sacara rinci kumaha ngabéréskeun masalah kasaluyuan database dina panyebaran. Kami bakal nyarioskeun ka anjeun naon anu tiasa kajantenan kana aplikasi produksi anjeun upami anjeun nyobian nyebarkeun tanpa persiapan awal. Urang teras bakal ngaliwat tahapan siklus hirup aplikasi anu diwajibkeun gaduh nol downtime (kira-kira. jalur: salajengna - enol downtime). Hasil tina operasi urang bakal nerapkeun parobahan database mundur-teu cocog dina cara mundur-cocog.

Upami anjeun hoyong ngartos conto kode tina artikel, anjeun tiasa mendakanana di GitHub.

perkenalan

Nol downtime deployment

Naon mistis enol downtime deployment? Anjeun tiasa nyebatkeun ieu nalika aplikasi anjeun disebarkeun ku cara anu anjeun tiasa suksés ngenalkeun vérsi énggal tina aplikasi kana produksi, sedengkeun pangguna henteu perhatikeun henteu sayogi. Tina sudut pandang pangguna sareng perusahaan, ieu mangrupikeun skénario panyebaran pangsaéna sabab ngamungkinkeun fitur anyar diwanohkeun sareng bug dibenerkeun tanpa gangguan.

Kumaha carana ngahontal ieu? Aya sababaraha cara, ieu salah sahijina:

  • nyebarkeun versi No.. 1 tina jasa anjeun
  • ngalakukeun migrasi database
  • Nyebarkeun versi #2 tina jasa anjeun paralel sareng versi #1
  • pas anjeun ningali yén versi No.. 2 jalan sakumaha sakuduna, cabut versi No.. 1
  • dipigawé!

Gampang, sanés? Hanjakalna, éta henteu saderhana, sareng urang bakal ningali éta sacara rinci engké. Ayeuna hayu urang parios prosés panyebaran anu cukup umum - blue green deployment .

Naha anjeun kantos nguping deployment héjo biru? Cloud Foundry ngajadikeun ieu gampang pisan. Ngan nempo artikel ieu, dimana urang ngajelaskeun ieu leuwih jéntré. Pikeun nyimpulkeun sakeudeung, hayu urang ngingetkeun anjeun kumaha panyebaran héjo biru:

  • mastikeun yén dua salinan kode produksi anjeun ("biru" jeung "héjo") jalan;
  • ngarahkeun sagala lalulintas ka lingkungan biru, i.e. ku kituna URL produksi nunjuk aya;
  • nyebarkeun sareng nguji sadaya parobihan aplikasi dina lingkungan héjo;
  • pindah url tina biru ka lingkungan héjo

Panyebaran héjo biru mangrupikeun pendekatan anu ngamungkinkeun anjeun gampang ngenalkeun fitur-fitur anyar tanpa hariwang ngeunaan pegatna produksi. Ieu alatan kanyataan yén sanajan aya kajadian, anjeun bisa kalayan gampang gulung deui ka lingkungan saméméhna ku saukur "nyintreuk saklar".

Saatos maca sadayana di luhur, anjeun tiasa naroskeun patarosan: Naon hubunganana enol downtime sareng penyebaran héjo Biru?

Nya, aranjeunna gaduh seueur anu umum, sabab ngajaga dua salinan lingkungan anu sami peryogi dua kali usaha pikeun ngajagaana. Ieu naha sababaraha tim ngaku Martin Fowler, tuturkeun variasi pendekatan ieu:

Pilihan séjén nyaéta ngagunakeun pangkalan data anu sami, nyiptakeun saklar biru-héjo pikeun wéb sareng lapisan domain. Dina pendekatan ieu, pangkalan data sering tiasa janten masalah, khususna nalika anjeun kedah ngarobih skéma pikeun ngadukung vérsi énggal parangkat lunak.

Sarta di dieu urang datang ka masalah utama dina artikel ieu. Basis data. Hayu urang tingali deui dina frasa ieu.

ngalakukeun migrasi database.

Ayeuna anjeun kedah naroskeun patarosan ka diri anjeun - kumaha upami parobihan database henteu cocog sareng mundur? Naha versi munggaran kuring tina aplikasi bakal rusak? Kanyataanna, ieu persis naon anu bakal kajadian ...

Janten, sanaos manpaat ageung tina nol downtime / panyebaran héjo biru, perusahaan condong nuturkeun prosés anu langkung aman pikeun nyebarkeun aplikasina:

  • nyiapkeun pakét sareng versi anyar tina aplikasi
  • mareuman hiji aplikasi ngajalankeun
  • ngajalankeun skrip pikeun migrasi database
  • nyebarkeun jeung ngajalankeun versi anyar tina aplikasi

Dina tulisan ieu, kami bakal ngajelaskeun kumaha anjeun tiasa damel sareng pangkalan data sareng kode anjeun pikeun ngamangpaatkeun panyebaran waktos downtime enol.

isu database

Upami anjeun gaduh aplikasi stateless anu henteu nyimpen data dina pangkalan data, anjeun tiasa langsung nampi panyebaran downtime enol. Hanjakalna, seueur parangkat lunak kedah nyimpen data dimana waé. Éta sababna anjeun kedah mikir dua kali sateuacan ngadamel parobihan kana sirkuit. Sateuacan urang terangkeun detil kumaha cara ngarobih skéma supados panyebaran henteu-downtime mungkin, hayu urang fokus heula kana skéma versi.

Skéma Vérsi

Dina artikel ieu kami bakal ngagunakeun Jalan layangan salaku alat kontrol versi (kira-kira. Tarjamahan: urang ngobrol ngeunaan migrasi database). Alami, urang ogé bakal nulis aplikasi Spring Boot nu geus diwangun-di rojongan Flyway sarta bakal ngalakukeun migrasi schema bari nyetel konteks aplikasi. Nalika nganggo Flyway, anjeun tiasa nyimpen skrip migrasi dina folder proyék anjeun (sacara standar di classpath:db/migration). Di dieu anjeun tiasa ningali conto file migrasi sapertos kitu

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

Dina conto ieu kami ningali 4 skrip migrasi anu, upami henteu dieksekusi sateuacana, bakal dieksekusi hiji-hiji nalika aplikasi dimimitian. Hayu urang tingali salah sahiji file (V1__init.sql) salaku conto.

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

Sagalana sampurna timer explanatory: Anjeun tiasa make SQL keur ngartikeun kumaha database Anjeun kudu dirobah. Kanggo inpo nu langkung lengkep ihwal Spring Boot jeung Flyway, pariksa kaluar Spring Boot Docs.

Ku ngagunakeun alat kontrol sumber kalawan Spring Boot, anjeun meunang 2 kauntungan badag:

  • Anjeun misahkeun parobahan database tina parobahan kode
  • Migrasi database lumangsung babarengan jeung rollout tina aplikasi Anjeun, i.e. prosés deployment anjeun disederhanakeun

Ngungkulan masalah database

Dina bagian salajengna artikel, urang bakal difokuskeun nempo dua pendekatan kana parobahan database.

  • sauyunan mundur
  • kasaluyuan mundur

Anu kahiji bakal dianggap salaku peringatan yén anjeun henteu kedah ngalaksanakeun panyebaran downtime enol tanpa persiapan awal.

Proyék kami anu bakal digarap bakal janten aplikasi Spring Boot Flyway saderhana anu gaduh Person с first_name и last_name dina pangkalan data (kira-kira. tarjamahan: Person mangrupa méja jeung first_name и last_name - ieu sawah di dinya). Urang rék ngaganti ngaran last_name в surname.

Anggapan

Sateuacan urang lebet kana detil, aya sababaraha asumsi anu kedah urang lakukeun ngeunaan aplikasi urang. Hasil utama anu urang hoyongkeun nyaéta prosés anu saderhana.

Catetan. Usaha PRO-TIP. Proses nyederhanakeun tiasa ngahémat artos anjeun pikeun ngadukung (beuki seueur jalma anu anjeun damel pikeun perusahaan anjeun, langkung seueur artos anjeun tiasa ngahemat)!

Teu perlu rollback database

Ieu simplifies prosés deployment (sababaraha rollbacks database ampir teu mungkin, kayaning rollback ngahapus). Urang leuwih resep gulung deui ngan aplikasi. Ku cara ieu, sanajan anjeun gaduh database béda (contona, SQL jeung NoSQL), pipe deployment anjeun bakal kasampak sarua.

Éta kedah salawasna tiasa ngagulung deui aplikasi hiji versi deui (henteu langkung)

Rollback ngan kudu dipigawé lamun perlu. Upami aya bug dina vérsi ayeuna anu henteu gampang dibenerkeun, urang kedah tiasa ngabalikan deui ka vérsi damel panganyarna. Kami nganggap yén vérsi kerja pangénggalna ieu mangrupikeun anu sateuacana. Ngajaga kasaluyuan kode sareng pangkalan data pikeun langkung ti hiji peluncuran bakal sesah pisan sareng mahal.

Catetan. Pikeun kabacaan anu langkung ageung, dina tulisan ieu kami bakal ngarobih versi utama aplikasi.

Lengkah 1: Kaayaan Awal

Vérsi aplikasi: 1.0.0
Vérsi DB: v1

komentar

Ieu bakal kaayaan awal aplikasi.

parobahan database

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

Parobahan kode

Aplikasi nyimpen data Person dina 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
                + "]";
    }
}

Ganti ngaran kolom anu teu cocog

Hayu urang nempo conto kumaha carana ngarobah ngaran kolom:

Perhatosan. Conto di handap ieu ngahaja bakal ngarecah hal. Kami nunjukkeun ieu pikeun nunjukkeun masalah kasaluyuan database.

Vérsi aplikasi: 2.0.0.BAD

Vérsi DB: v2bad

komentar

Parobahan ayeuna teu ngidinan urang ngajalankeun dua instansi (heubeul jeung anyar) dina waktos anu sareng. Ku kituna, enol downtime deployment bakal hésé pikeun ngahontal (lamun asumsi nu dicokot kana akun, éta sabenerna teu mungkin).

Uji A/B

Kaayaan ayeuna nyaéta yén urang gaduh versi aplikasi 1.0.0, deployed dina produksi, sarta database v1. Urang kedah nyebarkeun conto kadua aplikasi, versi 2.0.0.BAD, sarta ngapdet database ka v2bad.

Léngkah-léngkah:

  1. conto anyar tina aplikasi versi ieu deployed 2.0.0.BADnu ngamutahirkeun database ka v2bad
  2. dina database v2bad kolom last_name teu aya deui - eta dirobah jadi surname
  3. Pembaruan database sareng aplikasi suksés sareng sababaraha instansi jalan 1.0.0, batur - di 2.0.0.BAD. Sagalana disambungkeun ka database v2bad
  4. sagala conto versi 1.0.0 bakal ngamimitian ngalungkeun kasalahan sabab bakal nyobian nyelapkeun data kana kolom last_nameanu teu aya deui
  5. sagala conto versi 2.0.0.BAD bakal jalan tanpa masalah

Sakumaha anjeun tiasa tingali, upami urang ngadamel parobihan anu teu cocog sareng database sareng aplikasi, uji A/B mustahil.

Ngabalikeun aplikasi

Hayu urang nganggap yén saatos nyobian ngalaksanakeun penyebaran A/B (kira-kira. per .: pangarang meureun dimaksudkan A / B nguji dieu) urang mutuskeun yén urang kudu gulung deui aplikasi ka versi 1.0.0. Hayu urang nyebutkeun urang teu hayang rollback database.

Léngkah-léngkah:

  1. urang ngeureunkeun conto aplikasi versi 2.0.0.BAD
  2. pangkalan data masih v2bad
  3. saprak versi 1.0.0 teu ngartos naon éta surname, urang bakal ningali kasalahan
  4. naraka geus pegat leupas, urang teu bisa balik deui

Sakumaha anjeun tiasa tingali, lamun urang nyieun parobahan sauyunan mundur kana database jeung aplikasi, urang moal bisa balik deui ka versi saméméhna.

Log palaksanaan skrip

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

parobahan database

Aksara Migrasi nu ngaganti ngaran last_name в surname

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

Aksara nu ngaganti ngaran last_name.

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

Parobahan kode

Kami geus ngaganti ngaran widang lastName dina surname.

Ngaganti ngaran kolom dina cara mundur-cocog

Ieu mangrupikeun kaayaan anu paling umum anu urang tiasa tepang. Urang kudu nyieun parobahan sauyunan mundur. Kami parantos ngabuktikeun yén pikeun panyebaran enol-downtime, urang henteu kedah ngan saukur nerapkeun migrasi database tanpa léngkah tambahan. Dina bagian artikel ieu, urang bakal ngalakukeun 3 panyebaran aplikasi sareng migrasi database pikeun ngahontal hasil anu dipikahoyong bari ngajaga kasaluyuan mundur.

Catetan. Inget yen urang boga database versi v1. Ieu ngandung kolom first_name и last_name. Urang kudu ngarobah last_name dina surname. Kami ogé ngagaduhan versi aplikasi 1.0.0, anu henteu acan dianggo surname.

Lengkah 2: Tambahkeun ngaran kulawarga

Vérsi aplikasi: 2.0.0
Vérsi DB: v2

komentar

Ku nambahkeun kolom anyar jeung nyalin eusina, urang nyieun parobahan database cocog mundur. Dina waktos anu sami, upami urang ngabalikan JAR atanapi gaduh JAR anu lami, éta moal rusak nalika dieksekusi.

Kami ngaluncurkeun versi énggal

Léngkah-léngkah:

  1. ngalakukeun migrasi database pikeun nyieun kolom anyar surname. Ayeuna versi DB anjeun v2
  2. salinan data ti last_name в surname. Perhatikeunyén lamun geus loba data ieu, Anjeun kudu mertimbangkeun migrasi bets!
  3. nulis kode dimana aranjeunna dipaké DUA и новыйjeung lami kolom. Ayeuna versi aplikasi anjeun 2.0.0
  4. baca nilai tina kolom surname, lamun henteu null, atawa ti last_name, upami surname henteu ditangtoskeun. Anjeun tiasa mupus getLastName() ti kode, saprak éta bakal kaluaran null lamun rolling deui aplikasi anjeun ti 3.0.0 ka 2.0.0.

Upami anjeun nganggo Spring Boot Flyway, dua léngkah ieu bakal dilakukeun nalika ngamimitian versi 2.0.0 aplikasi. Upami anjeun ngajalankeun alat vérsi pangkalan data sacara manual, anjeun kedah ngalakukeun dua hal anu béda pikeun ngalakukeun ieu (mimiti ngapdet versi db sacara manual teras nyebarkeun aplikasi énggal).

Penting. Inget yén kolom karek dijieun KUDUNA HENTEU быть TEU NULIS. Lamun ngalakukeun rollback a, aplikasi heubeul teu nyaho ngeunaan kolom anyar jeung moal install deui salila Insert. Tapi lamun nambahan konstrain ieu sareng db anjeun bakal v2, ieu ngabutuhkeun netepkeun nilai kolom anyar. Nu bakal ngakibatkeun palanggaran larangan.

Penting. Anjeun kedah ngahapus metodeu getLastName(), sabab dina versi 3.0.0 Henteu aya konsép kolom dina kode éta last_name. Ieu ngandung harti yén null bakal disetél di dinya. Anjeun tiasa ninggalkeun metoda tur nambahkeun cék pikeun null, Tapi solusi leuwih hadé bakal pastikeun yén dina logika getSurname() Anjeun milih nilai non-enol bener.

Uji A/B

Kaayaan ayeuna nyaéta yén urang gaduh versi aplikasi 1.0.0, deployed on produksi, jeung database di v1. Urang kedah nyebarkeun conto kadua tina aplikasi versi 2.0.0nu bakal ngamutahirkeun database ka v2.

Léngkah-léngkah:

  1. conto anyar tina aplikasi versi ieu deployed 2.0.0nu ngamutahirkeun database ka v2
  2. Samentara éta sababaraha requests diolah ku instansi versi 1.0.0
  3. apdet éta suksés tur Anjeun gaduh sababaraha instansi ngajalankeun tina aplikasi versi 1.0.0 jeung versi séjén 2.0.0. Sarerea komunikasi sareng database di v2
  4. vérsi 1.0.0 teu make kolom surname dina database, tapi versi 2.0.0 kagunaan. Aranjeunna teu ngaganggu silih, sarta teu kudu aya kasalahan.
  5. vérsi 2.0.0 nyimpen data dina kolom heubeul jeung anyar, mastikeun kasaluyuan mundur

Penting. Upami anjeun gaduh patarosan anu ngitung barang dumasar kana nilai tina kolom lami/anyar, anjeun kedah émut yén anjeun ayeuna gaduh nilai duplikat (paling dipikaresep aranjeunna masih migrasi). Contona, upami anjeun hoyong cacah jumlah pamaké anu ngaran tukang (naon kolom disebut) dimimitian ku hurup A, teras dugi ka migrasi data réngsé (oldnew kolom) anjeun tiasa gaduh data anu teu konsisten upami anjeun naroskeun kolom énggal.

Ngabalikeun aplikasi

Ayeuna urang gaduh versi aplikasi 2.0.0 jeung database di v2.

Léngkah-léngkah:

  1. gulung deui aplikasi anjeun ka versi 1.0.0.
  2. vérsi 1.0.0 teu make kolom dina database surname, jadi rollback kudu suksés

parobahan DB

Database ngandung kolom ngaranna last_name.

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

Tambahkeun naskah surname.

Perhatosan. Émut yén anjeun TEU BISA TAMBAHkeun larangan NOT NULL kana kolom anu anjeun tambahkeun. Upami anjeun ngagulung deui JAR, versi anu lami henteu terang ngeunaan kolom anu ditambah sareng bakal otomatis disetel ka NULL. Upami aya watesan sapertos kitu, aplikasi anu lami ngan saukur bakal rusak.

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

Parobahan kode

Urang nyimpen data salaku last_namesareng di surname. Dina waktu nu sarua urang maca ti last_name, Kusabab kolom ieu paling relevan. Salila prosés panyebaran, sababaraha pamundut tiasa diolah ku conto aplikasi anu henteu acan diropéa.

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

Lengkah 3: Ngahapus last_name tina kode

Vérsi aplikasi: 3.0.0

Vérsi DB:v3

komentar

Catetan per .: Tétéla, dina artikel aslina panulis salah nyalin téks blok ieu ti hambalan 2. Dina hambalan ieu, parobahan kudu dilakukeun dina kode aplikasi aimed dina nyoplokkeun fungsionalitas nu ngagunakeun kolom. last_name.

Ku nambahkeun kolom anyar jeung nyalin eusina, urang nyieun parobahan database cocog mundur. Ogé, lamun urang rollback JAR atawa boga JAR heubeul ngajalankeun, éta moal megatkeun salila palaksanaan.

Ngabalikeun aplikasi

Ayeuna urang gaduh versi aplikasi 3.0.0 jeung database v3. Vérsi 3.0.0 teu nyimpen data ka last_name. Ieu ngandung harti yén dina surname inpo nu paling up-to-date disimpen.

Léngkah-léngkah:

  1. gulung deui aplikasi anjeun ka versi 2.0.0.
  2. vérsi 2.0.0 ngagunakeun jeung last_name и surname.
  3. vérsi 2.0.0 bakal nyandak surname, lamun teu nol, disebutkeun -last_name

parobahan database

Henteu aya parobahan struktural dina pangkalan data. Skrip di handap ieu dieksekusi pikeun ngalakukeun migrasi ahir data heubeul:

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

Parobahan kode

Catetan per .: Katerangan ngeunaan blok ieu ogé salah disalin ku panulis ti lengkah 2. Luyu jeung logika artikel, parobahan kode dina hambalan ieu kudu aimed dina miceun ti eta elemen anu hade jeung kolom. last_name.

Urang nyimpen data salaku last_namesareng di surname. Salaku tambahan, urang maca tina kolom last_name, saprak éta paling relevan. Salila prosés panyebaran, sababaraha pamundut tiasa diolah ku conto anu henteu acan ditingkatkeun.

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

Lengkah 4: Ngahapus last_name tina pangkalan data

Vérsi aplikasi: 4.0.0

Vérsi DB: v4

komentar

Alatan kanyataan yén kode versi 3.0.0 henteu nganggo kolom last_name, euweuh goréng bakal kajadian salila palaksanaan lamun urang gulung deui ka 3.0.0 sanggeus nyoplokkeun kolom tina database.

Log palaksanaan skrip

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

parobahan DB

Relatip v3 urang ngan miceun kolom last_name sareng tambahkeun larangan anu leungit.

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

Parobahan kode

Aya henteu parobahan kode.

kacindekan

Kami suksés nerapkeun parobahan ngaran kolom anu teu cocog sareng mundur ku ngalaksanakeun sababaraha panyebaran anu cocog sareng mundur. Di handap ieu kasimpulan tindakan anu dilakukeun:

  1. deployment versi aplikasi 1.0.0 с v1 skéma database (ngaran kolom = last_name)
  2. deployment versi aplikasi 2.0.0, nu nyimpen data dina last_name и surname. Aplikasi maca tina last_name. pangkalan data aya dina versi v2ngandung kolom kawas last_namejeung surname. surname mangrupa salinan last_name. (CATETAN: Kolom ieu teu kedah gaduh konstrain teu nol)
  3. deployment versi aplikasi 3.0.0, nu ngan nyimpen data dina surname sarta maca tina surname. Sedengkeun pikeun database, migrasi panungtungan lumangsung last_name в surname. Ogé watesan TEU NULIS dikaluarkeun tina last_name. Pangkalan data ayeuna aya dina versi v3
  4. deployment versi aplikasi 4.0.0 - euweuh parobahan dijieun pikeun kode. deployment database v4, nu ngaluarkeun last_name. Di dieu anjeun tiasa nambihan konstrain anu leungit kana pangkalan data.

Ku nuturkeun pendekatan ieu, anjeun salawasna bisa ngagulung deui hiji versi tanpa megatkeun database / kasaluyuan aplikasi.

kode

Sadaya kode anu dianggo dina tulisan ieu sayogi di Github. Di handap ieu pedaran tambahan.

Proyék

Saatos kloning gudang, anjeun bakal ningali struktur folder di handap ieu.

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

Naskah

Anjeun tiasa ngajalankeun skrip anu dijelaskeun dina skrip di handap ieu, anu bakal nunjukkeun parobihan anu cocog sareng teu cocog kana pangkalan data.

Ningali kasus kalawan parobahan cocog mundur, ngajalankeun:

./scripts/scenario_backward_compatible.sh

Jeung ningali kasus kalawan parobahan sauyunan mundur, ngajalankeun:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sampel Flyway

Sadaya conto dicokot tina Spring Boot Sample Flyway.

Anjeun tiasa nyandak katingal di http://localhost:8080/flyway, aya daptar naskah.

Conto ieu ogé kalebet konsol H2 (di http://localhost:8080/h2-console) sangkan anjeun tiasa ningali status database (URL jdbc standar nyaéta jdbc:h2:mem:testdb).

Sajaba

Baca ogé artikel séjén dina blog urang:

sumber: www.habr.com

Tambahkeun komentar