Zero Downtime Deployment lan Database

Zero Downtime Deployment lan Database

Artikel iki nerangake kanthi rinci babagan carane ngatasi masalah kompatibilitas database nalika nyebarake. Kita bakal ngandhani apa sing bisa kedadeyan ing aplikasi produksi yen sampeyan nyoba nyebarake tanpa persiapan awal. Banjur kita bakal ngliwati tahapan siklus urip aplikasi sing dibutuhake supaya ora mandheg nol (kira-kira. lane: luwih - nul downtime). Asil saka operasi kita bakal ngetrapake owah-owahan database sing ora kompatibel kanthi mundur kanthi cara sing kompatibel.

Yen sampeyan pengin ngerti conto kode saka artikel, sampeyan bisa nemokake ing GitHub.

Pambuka

Zero downtime panyebaran

Apa mistis panyebaran downtime nul? Sampeyan bisa ngomong iki nalika aplikasi sampeyan disebarake kanthi cara sing bisa ngenalake versi anyar aplikasi kasebut menyang produksi, nalika pangguna ora ngelingi ora kasedhiya. Saka perspektif pangguna lan perusahaan, iki minangka skenario panyebaran sing paling apik amarga ngidini fitur-fitur anyar dienalake lan bug bisa didandani tanpa gangguan.

Kepiye carane entuk iki? Ana sawetara cara, iki salah sijine:

  • masang versi No.. 1 layanan sampeyan
  • nindakake migrasi database
  • Pasang versi #2 saka layanan sampeyan kanthi podo karo versi #1
  • sanalika sampeyan ndeleng sing versi No.. 2 dianggo minangka ngirim, mbusak versi No.. 1
  • rampung!

Gampang, ta? Sayange, iku ora sing prasaja, lan kita bakal katon ing rinci mengko. Saiki ayo mriksa proses penyebaran liyane sing cukup umum - blue green deployment.

Apa sampeyan nate krungu babagan penyebaran ijo biru? Cloud Foundry ndadekake iki gampang banget. Delengen wae artikel iki, ngendi kita njlèntrèhaké iki ing liyane rinci. Kanggo ngringkes kanthi ringkes, ayo ngelingake sampeyan carane nggawe penyebaran ijo biru:

  • mesthekake yen rong salinan kode produksi ("biru" lan "ijo") bisa digunakake;
  • ngarahake kabeh lalu lintas menyang lingkungan biru, i.e. supaya URL produksi tumuju ing kana;
  • masang lan nyoba kabeh owah-owahan aplikasi ing lingkungan ijo;
  • ngalih url saka biru menyang lingkungan ijo

Penyebaran ijo biru minangka pendekatan sing ngidini sampeyan ngenalake fitur-fitur anyar kanthi gampang tanpa kuwatir babagan produksi. Iki amarga kasunyatane sanajan ana kedadeyan, sampeyan bisa kanthi gampang muter bali menyang lingkungan sadurunge kanthi mung "nggulung cepet saklar".

Sawise maca kabeh sing kasebut ing ndhuwur, sampeyan bisa uga takon: Apa hubungane nol downtime karo penyebaran ijo Biru?

Inggih, padha duwe cukup akèh ing umum, wiwit ngramut loro salinan saka lingkungan padha mbutuhake pindho gaweyan kanggo njaga. Iki sebabe sawetara tim ngaku Martin Fowler, tindakake variasi saka pendekatan iki:

Pilihan liyane yaiku nggunakake database sing padha, nggawe switch biru-ijo kanggo lapisan web lan domain. Ing pendekatan iki, database asring bisa dadi masalah, utamané nalika sampeyan kudu ngganti skema kanggo ndhukung versi anyar saka piranti lunak.

Lan ing kene kita teka menyang masalah utama ing artikel iki. Database. Ayo dipikir maneh ing ukara iki.

nindakake migrasi database.

Saiki sampeyan kudu takon dhewe - apa yen owah-owahan database ora kompatibel? Apa ora versi pisanan saka app break? Ing kasunyatan, iki persis apa sing bakal kelakon ...

Dadi, sanajan entuk manfaat gedhe saka panyebaran nol downtime / biru ijo, perusahaan cenderung ngetutake proses sing luwih aman kanggo ngetrapake aplikasi kasebut:

  • nyiyapake paket karo versi anyar saka aplikasi
  • mateni aplikasi sing mlaku
  • mbukak script kanggo migrasi database
  • masang lan miwiti versi anyar saka aplikasi

Ing artikel iki, kita bakal njlèntrèhaké cara sampeyan bisa nggarap basis data lan kode kanggo njupuk kauntungan saka penyebaran nol downtime.

Masalah database

Yen sampeyan duwe aplikasi stateless sing ora nyimpen data ing database, sampeyan bisa langsung njaluk panyebaran downtime nul. Sayange, akeh piranti lunak kudu nyimpen data ing endi wae. Mulane sampeyan kudu mikir kaping pindho sadurunge nggawe owah-owahan ing sirkuit. Sadurunge kita njlentrehake babagan carane ngganti skema supaya ora ana wektu downtime, ayo fokus ing skema versi.

Skema versi

Ing artikel iki kita bakal nggunakake Flyway minangka alat kontrol versi (kira-kira. Terjemahan: kita ngomong babagan migrasi database). Mesthi wae, kita uga bakal nulis aplikasi Spring Boot sing duwe dhukungan Flyway sing dibangun lan bakal nindakake migrasi skema nalika nyetel konteks aplikasi. Nalika nggunakake Flyway, sampeyan bisa nyimpen skrip migrasi ing folder proyek sampeyan (kanthi standar ing classpath:db/migration). Ing kene sampeyan bisa ndeleng conto file migrasi kasebut

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

Ing conto iki, kita ndeleng 4 skrip migrasi sing, yen ora dieksekusi sadurunge, bakal dieksekusi siji-sijine nalika aplikasi diwiwiti. Ayo ndeleng salah sawijining file (V1__init.sql) minangka 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');

Kabeh iku panjelasan dhewe: sampeyan bisa nggunakake SQL kanggo nemtokake cara database sampeyan kudu diowahi. Kanggo informasi luwih lengkap babagan Spring Boot lan Flyway, priksa Dokumen Spring Boot.

Kanthi nggunakake alat kontrol sumber karo Spring Boot, sampeyan entuk 2 keuntungan gedhe:

  • sampeyan misahake owah-owahan database saka owah-owahan kode
  • Migrasi database dumadi bebarengan karo rollout saka aplikasi, i.e. proses penyebaran Panjenengan wis simplified

Ngatasi masalah database

Ing bagean sabanjure artikel, kita bakal fokus kanggo ndeleng rong pendekatan kanggo owah-owahan database.

  • incompatibility mundur
  • kompatibilitas mundur

Sing pisanan bakal dianggep minangka bebaya yen sampeyan ora kudu nindakake panyebaran downtime nul tanpa persiapan awal... Kapindho menehi solusi babagan carane sampeyan bisa nindakake penyebaran tanpa downtime lan ing wektu sing padha njaga kompatibilitas mundur.

Proyèk kita sing bakal digarap bakal dadi aplikasi Spring Boot Flyway sing prasaja Person с first_name и last_name ing basis data (kira-kira. ngartekne: Person yaiku tabel lan first_name и last_name - iki lapangan ing). Kita pengin ngganti jeneng last_name в surname.

Asumsi

Sadurunge kita entuk rincian, ana sawetara asumsi sing kudu kita lakoni babagan aplikasi kita. Asil utama sing pengin digayuh bakal dadi proses sing cukup prasaja.

Cathetan. Bisnis PRO-TIP. Proses nyederhanakake bisa ngirit dhuwit akeh kanggo dhukungan (luwih akeh wong sing kerja ing perusahaan sampeyan, luwih akeh dhuwit sampeyan bisa ngirit)!

Ora perlu mbatalake database

Iki nyederhanakake proses panyebaran (sawetara mbalek maneh database meh ora mungkin, kayata mbalekake pambusakan). Kita luwih seneng muter maneh mung aplikasi. Kanthi cara iki, sanajan sampeyan duwe database beda (contone, SQL lan NoSQL), pipeline penyebaran sampeyan bakal katon padha.

Sampeyan kudu tansah bisa muter maneh aplikasi siji versi maneh (ora luwih)

Rollback mung kudu ditindakake yen perlu. Yen ana bug ing versi saiki sing ora gampang didandani, kita kudu bisa bali menyang versi kerja paling anyar. Kita nganggep manawa versi kerja paling anyar iki minangka versi sadurunge. Njaga kompatibilitas kode lan database kanggo luwih saka siji rollout bakal angel banget lan larang.

Cathetan kasebut. Kanggo luwih gampang diwaca, ing artikel iki kita bakal ngganti versi utama aplikasi kasebut.

Langkah 1: State Initial

Versi app: 1.0.0
Versi DB: v1

komentar

Iki bakal dadi negara wiwitan aplikasi.

owah-owahan database

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

Owah-owahan kode

Aplikasi nyimpen data Person ing 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 jeneng kolom sing ora kompatibel

Ayo goleki conto carane ngganti jeneng kolom:

Manungsa waé. Conto ing ngisor iki kanthi sengaja bakal ngilangi barang. Kita nuduhake iki kanggo nduduhake masalah kompatibilitas database.

Versi app: 2.0.0.BAD

Versi DB: v2bad

komentar

Owah-owahan saiki ora ngidini kita mbukak rong instansi (lawas lan anyar) bebarengan. Mangkono, panyebaran downtime nul bakal angel digayuh (yen anggepan dianggep, pancen ora mungkin).

Tes A/B

Kahanan saiki yaiku kita duwe versi aplikasi 1.0.0, disebarake ing produksi, lan database v1. Kita kudu masang conto liya saka aplikasi, versi 2.0.0.BAD, lan nganyari database kanggo v2bad.

Langkah:

  1. conto anyar saka aplikasi versi disebarake 2.0.0.BADkang nganyari database kanggo v2bad
  2. ing basis data v2bad kolom last_name ora ana maneh - diganti dadi surname
  3. Nganyari basis data lan aplikasi kasil lan sawetara kasus lagi mlaku 1.0.0, liyane - ing 2.0.0.BAD. Kabeh disambungake menyang database v2bad
  4. kabeh conto versi 1.0.0 bakal miwiti mbuwang kesalahan amarga bakal nyoba nglebokake data menyang kolom last_namesing wis ora ana maneh
  5. kabeh conto versi 2.0.0.BAD bakal bisa tanpa masalah

Kaya sing sampeyan ngerteni, yen kita nggawe owah-owahan sing ora cocog karo database lan aplikasi, tes A/B ora mungkin.

Aplikasi rollback

Ayo nganggep yen sawise nyoba nindakake penyebaran A/B (kira-kira. per .: penulis mbokmenawa temenan A / B testing kene) kita mutusaké sing kita kudu muter maneh aplikasi kanggo versi 1.0.0. Ayo ngomong kita ora pengin mbalek maneh database.

Langkah:

  1. kita mungkasi conto aplikasi versi 2.0.0.BAD
  2. database isih v2bad
  3. wiwit versi 1.0.0 ora ngerti apa iku surname, kita bakal weruh kasalahan
  4. neraka wis rusak ngeculke, kita ora bisa bali maneh

Kaya sing sampeyan ngerteni, yen kita nggawe owah-owahan sing ora kompatibel ing basis data lan aplikasi, kita ora bisa muter maneh menyang versi sadurunge.

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

owah-owahan database

Skrip Migrasi sing ganti jeneng last_name в surname

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

Skrip sing ganti jeneng last_name.

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

Owah-owahan kode

Kita wis ngganti jeneng lapangan lastName ing surname.

Ganti jeneng kolom kanthi cara sing cocog karo mundur

Iki minangka kahanan sing paling umum sing bisa kita temoni. Kita kudu nggawe owah-owahan sing ora cocog. Kita wis mbuktekake manawa kanggo panyebaran zero-downtime, kita ora mung kudu ngetrapake migrasi database tanpa langkah tambahan. Ing bagean artikel iki, kita bakal nindakake 3 panyebaran aplikasi bebarengan karo migrasi database kanggo entuk asil sing dikarepake nalika njaga kompatibilitas mundur.

Cathetan. Elinga yen kita duwe database versi v1. Isine kolom first_name и last_name. Kita kudu ngganti last_name ing surname. Kita uga duwe versi app 1.0.0, sing durung dienggo surname.

Langkah 2: Tambah jeneng

Versi app: 2.0.0
Versi DB: v2

komentar

Kanthi nambahake kolom anyar lan nyalin isine, kita nggawe owah-owahan database sing kompatibel. Ing wektu sing padha, yen kita muter maneh JAR utawa duwe JAR lawas mlaku, iku ora bakal break sak eksekusi.

We are Rolling metu versi anyar

Langkah:

  1. nindakake migrasi database kanggo nggawe kolom anyar surname. Saiki versi DB sampeyan v2
  2. salinan data saka last_name в surname. Delengenyen sampeyan duwe akeh data iki, sampeyan kudu nimbang migrasi kumpulan!
  3. nulis kode ngendi padha digunakake KARO и новыйlan sing lawas kolom. Saiki versi app sampeyan 2.0.0
  4. maca Nilai saka kolom surname, yen ora null, utawa saka last_nameyen surname gak di jelasno. Sampeyan bisa mbusak getLastName() saka kode, awit iku bakal output null nalika muter maneh aplikasi saka 3.0.0 kanggo 2.0.0.

Yen sampeyan nggunakake Spring Boot Flyway, rong langkah iki bakal ditindakake sajrone wiwitan versi 2.0.0 aplikasi. Yen sampeyan mbukak alat versi database kanthi manual, sampeyan kudu nindakake rong perkara sing beda kanggo nindakake iki (pisanan nganyari versi db kanthi manual banjur pasang aplikasi anyar).

Penting. Elinga yen kolom sing mentas digawe KUDUNE ORA dadi ORA NULUNG. Yen sampeyan nindakake rollback, aplikasi lawas ora ngerti babagan kolom anyar lan ora bakal nginstal sajrone Insert. Nanging yen sampeyan nambah watesan iki lan db bakal v2, iki mbutuhake nyetel nilai kolom anyar. Sing bakal nyebabake nglanggar larangan.

Penting. Sampeyan kudu mbusak cara getLastName(), amarga ing versi 3.0.0 Ora ana konsep kolom ing kode kasebut last_name. Iki tegese null bakal disetel ana. Sampeyan bisa ninggalake cara lan nambah mriksa kanggo null, nanging solusi sing luwih apik bakal nggawe manawa ing logika getSurname() sampeyan milih nilai non-nol sing bener.

Tes A/B

Kahanan saiki yaiku kita duwe versi aplikasi 1.0.0, disebarake ing produksi, lan database ing v1. Kita kudu masang conto liya saka aplikasi versi 2.0.0kang bakal nganyari database kanggo v2.

Langkah:

  1. conto anyar saka aplikasi versi disebarake 2.0.0kang nganyari database kanggo v2
  2. sauntara sawetara panjalukan diproses dening versi versi 1.0.0
  3. nganyari iki sukses lan sampeyan duwe sawetara kedadean mlaku saka aplikasi versi 1.0.0 lan versi liyane 2.0.0. Saben uwong komunikasi karo database ing v2
  4. versi 1.0.0 ora nggunakake kolom surname ing database, nanging versi 2.0.0 migunakake. Padha ora ngganggu saben liyane, lan ora ana kesalahan.
  5. versi 2.0.0 nyimpen data ing kolom lawas lan anyar, njamin kompatibilitas mundur

Penting. Yen sampeyan duwe pitakon sing ngitung item adhedhasar nilai saka kolom lawas/anyar, sampeyan kudu ngelingi yen sampeyan saiki duwe nilai duplikat (kemungkinan isih migrasi). Contone, yen sampeyan pengin ngetung jumlah pangguna sing jenenge mburi (apa wae kolom kasebut) diwiwiti kanthi huruf kasebut A, banjur nganti migrasi data rampung (oldnew kolom) sampeyan bisa uga duwe data sing ora konsisten yen sampeyan takon kolom anyar.

Aplikasi rollback

Saiki kita duwe versi app 2.0.0 lan database ing v2.

Langkah:

  1. gulung maneh aplikasi sampeyan menyang versi 1.0.0.
  2. versi 1.0.0 ora nggunakake kolom ing database surname, dadi rollback kudu sukses

owah-owahan DB

Database ngemot kolom sing jenenge 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');

Tambah script surname.

Manungsa waé. Elinga yen sampeyan ora bisa nambah watesan NOT NULL menyang kolom sing ditambahake. Yen sampeyan muter maneh JAR, versi lawas ora bakal ngerti babagan kolom sing ditambahake lan bakal kanthi otomatis nyetel menyang NULL. Yen ana watesan kasebut, aplikasi lawas mung 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

Owah-owahan kode

We nyimpen data minangka last_namelan ing surname. Ing wektu sing padha kita maca saka last_name, amarga kolom iki paling relevan. Sajrone proses panyebaran, sawetara panjalukan bisa uga wis diproses dening conto aplikasi sing durung dianyari.

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

Langkah 3: Mbusak last_name saka kode

Versi app: 3.0.0

Versi DB:v3

komentar

Cathetan per .: Ketoke, ing artikel asli penulis salah nyalin teks blok iki saka langkah 2. Ing langkah iki, owah-owahan kudu digawe ing kode aplikasi ngarahke kanggo mbusak fungsi sing nggunakake kolom last_name.

Kanthi nambahake kolom anyar lan nyalin isine, kita nggawe owah-owahan basis data sing kompatibel. Uga, yen kita muter maneh JAR utawa duwe JAR lawas mlaku, iku ora bakal break sak eksekusi.

Aplikasi rollback

Saiki kita duwe versi app 3.0.0 lan database v3. Versi 3.0.0 ora nyimpen data kanggo last_name. Iki tegese ing surname informasi paling anyar disimpen.

Langkah:

  1. gulung maneh aplikasi sampeyan menyang versi 2.0.0.
  2. versi 2.0.0 migunakake lan last_name и surname.
  3. versi 2.0.0 bakal njupuk surname, yen ora nol, yen ora -last_name

owah-owahan database

Ora ana owah-owahan struktural ing basis data. Skrip ing ngisor iki dieksekusi kanggo nindakake migrasi pungkasan data lawas:

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

Owah-owahan kode

Cathetan per .: Katrangan babagan pemblokiran iki uga salah disalin dening penulis saka langkah 2. Sesuai karo logika artikel, owah-owahan ing kode ing langkah iki kudu ngarahake kanggo mbusak saka unsur sing bisa digunakake karo kolom. last_name.

We nyimpen data minangka last_namelan ing surname. Kajaba iku, kita maca saka kolom last_name, awit iku paling relevan. Sajrone proses panyebaran, sawetara panjalukan bisa diproses dening conto sing durung dianyari.

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

Langkah 4: Mbusak last_name saka database

Versi app: 4.0.0

Versi DB: v4

komentar

Amarga kasunyatan sing kode versi 3.0.0 ora nggunakake kolom last_name, ora ana sing ala bakal kelakon sak eksekusi yen kita muter bali menyang 3.0.0 sawise mbusak kolom saka database.

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

owah-owahan DB

Relatif v3 kita mung mbusak kolom last_name lan nambah watesan sing ilang.

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

Owah-owahan kode

Ora ana owah-owahan ing kode.

kesimpulan

Kita kasil ngetrapake pangowahan jeneng kolom sing ora kompatibel kanthi mundur kanthi nindakake sawetara panyebaran sing kompatibel mundur. Ing ngisor iki ringkesan saka tumindak sing ditindakake:

  1. panyebaran versi aplikasi 1.0.0 с v1 skema database (nama kolom = last_name)
  2. panyebaran versi aplikasi 2.0.0, kang nyimpen data ing last_name и surname. Aplikasi maca saka last_name. Database ana ing versi v2ngemot kolom kaya last_namelan surname. surname iku salinan last_name. (CATETAN: Kolom iki kudu ora duwe watesan ora null)
  3. panyebaran versi aplikasi 3.0.0, sing mung nyimpen data ing surname lan maca saka surname. Kanggo database, migrasi pungkasan lagi ditindakake last_name в surname. Uga watesan ORA NULUNG dibusak saka last_name. Database saiki ana ing versi v3
  4. panyebaran versi aplikasi 4.0.0 - ora ana owah-owahan ing kode. panyebaran database v4, kang mbusak last_name. Ing kene sampeyan bisa nambahake watesan sing ilang menyang database.

Kanthi tindakake pendekatan iki, sampeyan bisa tansah muter siji versi tanpa break database / kompatibilitas aplikasi.

Kode

Kabeh kode sing digunakake ing artikel iki kasedhiya ing GitHub. Ing ngisor iki ana katrangan tambahan.

Proyek

Sawise kloning repositori, sampeyan bakal weruh struktur folder ing ngisor iki.

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

Sampeyan bisa mbukak skrip sing diterangake ing skrip ing ngisor iki, sing bakal nuduhake owah-owahan sing kompatibel lan ora kompatibel ing basis data.

Kanggo ndeleng kasus karo owah-owahan kompatibel mundur, mlaku:

./scripts/scenario_backward_compatible.sh

Lan kanggo ndeleng kasus karo owah-owahan sing ora kompatibel mundur, mlaku:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Kabeh conto dijupuk saka Spring Boot Sample Flyway.

Sampeyan bisa njupuk dipikir ing http://localhost:8080/flyway, ana dhaptar skrip.

Conto iki uga kalebu konsol H2 (ing http://localhost:8080/h2-console) supaya sampeyan bisa ndeleng status database (URL jdbc standar yaiku jdbc:h2:mem:testdb).

tambahan

Uga maca artikel liyane ing blog kita:

Source: www.habr.com

Add a comment