Penerapan dan Pangkalan Data Masa Henti Sifar

Penerapan dan Pangkalan Data Masa Henti Sifar

Artikel ini menerangkan secara terperinci cara menyelesaikan isu keserasian pangkalan data dalam penggunaan. Kami akan memberitahu anda perkara yang boleh berlaku kepada aplikasi pengeluaran anda jika anda cuba menggunakan tanpa persediaan awal. Kami kemudian akan melalui peringkat kitaran hayat aplikasi yang diperlukan untuk mempunyai masa henti sifar (lebih kurang lorong: lanjut - masa henti sifar). Hasil daripada operasi kami adalah untuk menggunakan perubahan pangkalan data yang tidak serasi ke belakang dengan cara yang serasi ke belakang.

Jika anda ingin memahami contoh kod daripada artikel, anda boleh menemuinya di GitHub.

Pengenalan

Penggunaan masa henti sifar

Sungguh mistik penggunaan masa henti sifar? Anda boleh mengatakan ini adalah apabila aplikasi anda digunakan dalam cara yang anda boleh berjaya memperkenalkan versi baharu aplikasi kepada pengeluaran, sementara pengguna tidak menyedari ketiadaannya. Dari perspektif pengguna dan syarikat, ini adalah senario penggunaan terbaik kerana ia membolehkan ciri baharu diperkenalkan dan pepijat diperbaiki tanpa gangguan.

Bagaimana untuk mencapai ini? Terdapat beberapa cara, berikut adalah salah satu daripadanya:

  • gunakan versi No. 1 perkhidmatan anda
  • melakukan migrasi pangkalan data
  • Gunakan versi #2 perkhidmatan anda selari dengan versi #1
  • sebaik sahaja anda melihat versi No. 2 berfungsi sebagaimana mestinya, alih keluar versi No. 1
  • selesai!

Mudah, bukan? Malangnya, ia tidak semudah itu, dan kami akan melihatnya secara terperinci kemudian. Sekarang mari kita semak satu lagi proses penggunaan yang agak biasa - penggunaan hijau biru.

Adakah anda pernah mendengar penempatan hijau biru? Cloud Foundry menjadikannya sangat mudah. Lihat sahaja artikel ini, di mana kami menerangkan perkara ini dengan lebih terperinci. Untuk meringkaskan secara ringkas, izinkan kami mengingatkan anda cara melakukan penempatan hijau biru:

  • pastikan dua salinan kod pengeluaran anda (“biru” dan “hijau”) berfungsi;
  • arahkan semua lalu lintas ke persekitaran biru, i.e. supaya URL pengeluaran menghala ke sana;
  • menggunakan dan menguji semua perubahan aplikasi dalam persekitaran hijau;
  • tukar url daripada persekitaran biru kepada hijau

Penggunaan hijau biru ialah pendekatan yang membolehkan anda memperkenalkan ciri baharu dengan mudah tanpa perlu risau tentang pemecahan pengeluaran. Ini disebabkan oleh fakta bahawa walaupun sesuatu berlaku, anda boleh kembali ke persekitaran sebelumnya dengan mudah dengan hanya "menjentik suis".

Selepas membaca semua perkara di atas, anda boleh bertanya soalan: Apakah kaitan masa henti sifar dengan penggunaan hijau Biru?

Nah, mereka mempunyai banyak persamaan, kerana mengekalkan dua salinan persekitaran yang sama memerlukan usaha berganda untuk mengekalkannya. Itulah sebabnya beberapa pasukan mendakwa Martin Fowler, ikut variasi pendekatan ini:

Pilihan lain ialah menggunakan pangkalan data yang sama, mencipta suis biru-hijau untuk web dan lapisan domain. Dalam pendekatan ini, pangkalan data selalunya boleh menjadi masalah, terutamanya apabila anda perlu menukar skemanya untuk menyokong versi baharu perisian.

Dan di sini kita sampai kepada masalah utama dalam artikel ini. Pangkalan data. Mari kita lihat lagi frasa ini.

melakukan migrasi pangkalan data.

Sekarang anda perlu bertanya kepada diri sendiri - bagaimana jika perubahan pangkalan data tidak serasi ke belakang? Bukankah versi pertama apl saya akan rosak? Sebenarnya, inilah yang akan berlaku...

Oleh itu, walaupun terdapat faedah besar daripada penggunaan masa henti sifar / hijau biru, syarikat cenderung mengikuti proses yang lebih selamat berikut untuk menggunakan aplikasi mereka:

  • sediakan pakej dengan versi baharu aplikasi
  • menutup aplikasi yang sedang berjalan
  • jalankan skrip untuk memindahkan pangkalan data
  • menggunakan dan melancarkan versi baharu aplikasi

Dalam artikel ini, kami akan memperincikan cara anda boleh bekerja dengan pangkalan data dan kod anda untuk memanfaatkan penggunaan masa henti sifar.

Isu pangkalan data

Jika anda mempunyai aplikasi tanpa kewarganegaraan yang tidak menyimpan sebarang data dalam pangkalan data, anda boleh mendapatkan penggunaan masa henti sifar serta-merta. Malangnya, kebanyakan perisian perlu menyimpan data di suatu tempat. Inilah sebabnya mengapa anda harus berfikir dua kali sebelum membuat sebarang perubahan pada litar. Sebelum kita masuk ke butiran tentang cara menukar skema supaya penggunaan tanpa masa henti boleh dilakukan, mari kita fokus dahulu pada skema versi.

Skim versi

Dalam artikel ini kami akan gunakan Laluan terbang sebagai alat kawalan versi (lebih kurang Terjemahan: kita bercakap tentang migrasi pangkalan data). Sememangnya, kami juga akan menulis aplikasi Spring Boot yang mempunyai sokongan Flyway terbina dalam dan akan melaksanakan migrasi skema semasa menyediakan konteks aplikasi. Apabila menggunakan Flyway, anda boleh menyimpan skrip migrasi dalam folder projek anda (secara lalai dalam classpath:db/migration). Di sini anda boleh melihat contoh fail migrasi sedemikian

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

Dalam contoh ini kita melihat 4 skrip migrasi yang, jika tidak dilaksanakan sebelum ini, akan dilaksanakan satu demi satu apabila aplikasi bermula. Mari lihat salah satu fail (V1__init.sql) sebagai contoh.

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

Segala-galanya jelas sendiri: anda boleh menggunakan SQL untuk menentukan cara pangkalan data anda harus diubah suai. Untuk maklumat lanjut tentang Spring Boot dan Flyway, lihat Dokumen Spring Boot.

Dengan menggunakan alat kawalan sumber dengan Spring Boot, anda mendapat 2 faedah besar:

  • anda memisahkan perubahan pangkalan data daripada perubahan kod
  • Penghijrahan pangkalan data berlaku bersama-sama dengan pelancaran aplikasi anda, i.e. proses penempatan anda dipermudahkan

Menyelesaikan masalah pangkalan data

Dalam bahagian artikel seterusnya, kami akan menumpukan pada melihat dua pendekatan kepada perubahan pangkalan data.

  • ketidakserasian ke belakang
  • keserasian ke belakang

Yang pertama akan dianggap sebagai amaran bahawa anda tidak seharusnya melakukan penggunaan masa henti sifar tanpa persediaan awal... Yang kedua menawarkan penyelesaian tentang cara anda boleh melaksanakan penggunaan tanpa masa henti dan pada masa yang sama mengekalkan keserasian ke belakang.

Projek kami yang akan kami usahakan ialah aplikasi Spring Boot Flyway yang mudah Person с first_name и last_name dalam pangkalan data (lebih kurang terjemahan: Person ialah jadual dan first_name и last_name - ini adalah bidang di dalamnya). Kami mahu menukar nama last_name в surname.

Andaian

Sebelum kita masuk ke butiran, terdapat beberapa andaian yang perlu kita buat tentang permohonan kita. Hasil utama yang ingin kami capai adalah proses yang agak mudah.

nota itu. PETUA PRO Perniagaan. Memudahkan proses boleh menjimatkan banyak wang untuk sokongan (lebih ramai orang yang anda bekerja untuk syarikat anda, lebih banyak wang yang anda boleh simpan)!

Tidak perlu rollback pangkalan data

Ini memudahkan proses penggunaan (sesetengah pemulangan pangkalan data hampir mustahil, seperti pemulangan semula pemadaman). Kami lebih suka untuk melancarkan semula aplikasi sahaja. Dengan cara ini, walaupun anda mempunyai pangkalan data yang berbeza (contohnya, SQL dan NoSQL), saluran paip penggunaan anda akan kelihatan sama.

Ia mesti SENTIASA boleh menggulung semula aplikasi satu versi kembali (tidak lebih)

Pemulangan semula hanya perlu dilakukan apabila perlu. Jika terdapat pepijat dalam versi semasa yang tidak mudah dibetulkan, kita sepatutnya boleh berbalik kepada versi terkini yang berfungsi. Kami menganggap bahawa versi terkini yang berfungsi ini adalah versi sebelumnya. Mengekalkan kod dan keserasian pangkalan data untuk lebih daripada satu pelancaran akan menjadi amat sukar dan mahal.

Nota itu. Untuk kebolehbacaan yang lebih baik, dalam artikel ini kami akan menukar versi utama aplikasi.

Langkah 1: Keadaan Awal

Versi aplikasi: 1.0.0
Versi DB: v1

Komen

Ini akan menjadi keadaan awal permohonan.

Perubahan pangkalan data

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

Perubahan kod

Aplikasi menyimpan data Orang dalam 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
                + "]";
    }
}

Penamaan semula lajur tidak serasi ke belakang

Mari lihat contoh cara menukar nama lajur:

Perhatian. Contoh berikut dengan sengaja akan memecahkan perkara. Kami menunjukkan ini untuk menunjukkan masalah keserasian pangkalan data.

Versi aplikasi: 2.0.0.BAD

Versi DB: v2bad

Komen

Perubahan semasa TIDAK membenarkan kami menjalankan dua kejadian (lama dan baharu) pada masa yang sama. Oleh itu, penggunaan masa henti sifar akan sukar dicapai (jika andaian diambil kira, ia sebenarnya mustahil).

Ujian A/B

Keadaan semasa ialah kami mempunyai versi aplikasi 1.0.0, digunakan dalam pengeluaran, dan pangkalan data v1. Kita perlu menggunakan contoh kedua aplikasi, versi 2.0.0.BAD, dan kemas kini pangkalan data kepada v2bad.

Langkah-langkah:

  1. contoh baharu aplikasi versi digunakan 2.0.0.BADyang mengemas kini pangkalan data kepada v2bad
  2. dalam pangkalan data v2bad ruangan last_name tidak lagi wujud - ia telah ditukar kepada surname
  3. Kemas kini pangkalan data dan aplikasi berjaya dan beberapa keadaan sedang berjalan 1.0.0, yang lain - dalam 2.0.0.BAD. Semuanya disambungkan ke pangkalan data v2bad
  4. semua contoh versi 1.0.0 akan mula membuang ralat kerana mereka akan cuba memasukkan data ke dalam lajur last_nameyang sudah tidak wujud lagi
  5. semua contoh versi 2.0.0.BAD akan berfungsi tanpa masalah

Seperti yang anda lihat, jika kami membuat perubahan yang tidak serasi ke belakang pada pangkalan data dan aplikasi, ujian A/B adalah mustahil.

Pemulangan semula permohonan

Mari kita anggap bahawa selepas cuba melakukan penempatan A/B (lebih kurang per.: penulis mungkin maksudkan ujian A/B di sini) kami memutuskan bahawa kami perlu melancarkan semula aplikasi kepada versi 1.0.0. Katakan kita tidak mahu mengembalikan pangkalan data.

Langkah-langkah:

  1. kami menghentikan contoh aplikasi versi 2.0.0.BAD
  2. pangkalan data masih ada v2bad
  3. sejak versi 1.0.0 tidak faham apa itu surname, kita akan melihat ralat
  4. neraka telah terlepas, kita tidak boleh kembali lagi

Seperti yang anda lihat, jika kami membuat perubahan yang tidak serasi ke belakang pada pangkalan data dan aplikasi, kami tidak boleh kembali ke versi sebelumnya.

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

Perubahan pangkalan data

Skrip migrasi yang menamakan semula last_name в surname

Skrip Flyway Sumber:

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 yang menamakan semula last_name.

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

Perubahan kod

Kami telah menukar nama medan lastName pada surname.

Menamakan semula lajur dengan cara yang serasi ke belakang

Ini adalah situasi paling biasa yang mungkin kita hadapi. Kita perlu membuat perubahan yang tidak serasi ke belakang. Kami telah membuktikan bahawa untuk penggunaan masa henti sifar, kami tidak seharusnya hanya menggunakan migrasi pangkalan data tanpa langkah tambahan. Dalam bahagian artikel ini, kami akan melaksanakan 3 penggunaan aplikasi bersama-sama dengan pemindahan pangkalan data untuk mencapai hasil yang diinginkan sambil mengekalkan keserasian ke belakang.

nota itu. Ingat bahawa kami mempunyai pangkalan data versi v1. Ia mengandungi lajur first_name и last_name. Kita kena berubah last_name pada surname. Kami juga mempunyai versi apl 1.0.0, yang masih belum digunakan surname.

Langkah 2: Tambahkan nama keluarga

Versi aplikasi: 2.0.0
Versi DB: v2

Komen

Dengan menambah lajur baharu dan menyalin kandungannya, kami mencipta perubahan pangkalan data yang serasi ke belakang. Pada masa yang sama, jika kita memutar balik JAR atau menjalankan JAR lama, ia tidak akan pecah semasa pelaksanaan.

Kami sedang melancarkan versi baharu

Langkah-langkah:

  1. lakukan pemindahan pangkalan data untuk mencipta lajur baharu surname. Sekarang versi DB anda v2
  2. salin data daripada last_name в surname. Perhatikanbahawa jika anda mempunyai banyak data ini, anda harus mempertimbangkan penghijrahan kelompok!
  3. tulis kod di mana ia digunakan KEDUANYA и barudan yang lama kolum. Kini versi apl anda 2.0.0
  4. baca nilai dari lajur surname, jika tidak null, atau daripada last_namejika surname tidak dinyatakan. Anda boleh memadam getLastName() daripada kod, kerana ia akan dikeluarkan null apabila melancarkan semula permohonan anda daripada 3.0.0 kepada 2.0.0.

Jika anda menggunakan Spring Boot Flyway, kedua-dua langkah ini akan dilakukan semasa versi permulaan 2.0.0 aplikasi. Jika anda menjalankan alat versi pangkalan data secara manual, anda perlu melakukan dua perkara berbeza untuk melakukan ini (mula-mula kemas kini versi db secara manual dan kemudian gunakan aplikasi baharu).

Ia penting. Ingat bahawa lajur yang baru dibuat TIDAK PATUT menjadi BUKAN NULL. Jika anda melakukan rollback, aplikasi lama tidak mengetahui tentang lajur baharu dan tidak akan memasangnya semasa Insert. Tetapi jika anda menambah kekangan ini dan db anda akan menjadi v2, ini memerlukan penetapan nilai lajur baharu. Yang akan membawa kepada pelanggaran sekatan.

Ia penting. Anda harus mengalih keluar kaedah getLastName(), kerana dalam versi 3.0.0 Tiada konsep lajur dalam kod last_name. Ini bermakna null akan ditetapkan di sana. Anda boleh meninggalkan kaedah dan menambah semakan untuk null, tetapi penyelesaian yang lebih baik adalah untuk memastikan bahawa dalam logik getSurname() anda memilih nilai bukan sifar yang betul.

Ujian A/B

Keadaan semasa ialah kami mempunyai versi aplikasi 1.0.0, digunakan pada pengeluaran, dan pangkalan data dalam v1. Kami perlu menggunakan contoh kedua aplikasi versi 2.0.0yang akan mengemas kini pangkalan data kepada v2.

Langkah-langkah:

  1. contoh baharu aplikasi versi digunakan 2.0.0yang mengemas kini pangkalan data kepada v2
  2. Sementara itu, beberapa permintaan telah diproses oleh contoh versi 1.0.0
  3. kemas kini telah berjaya dan anda mempunyai beberapa contoh aplikasi versi yang sedang berjalan 1.0.0 dan versi lain 2.0.0. Semua orang berkomunikasi dengan pangkalan data dalam v2
  4. versi 1.0.0 tidak menggunakan lajur nama keluarga dalam pangkalan data, tetapi versi 2.0.0 kegunaan. Mereka tidak mengganggu satu sama lain, dan tidak sepatutnya ada kesilapan.
  5. versi 2.0.0 menyimpan data dalam lajur lama dan baharu, memastikan keserasian ke belakang

Ia penting. Jika anda mempunyai sebarang pertanyaan yang mengira item berdasarkan nilai dari lajur lama/baharu, anda harus ingat bahawa anda kini mempunyai nilai pendua (kemungkinan besar ia masih berhijrah). Sebagai contoh, jika anda ingin mengira bilangan pengguna yang nama akhir mereka (apa sahaja nama lajur itu) bermula dengan huruf A, kemudian sehingga pemindahan data selesai (oldnew lajur) anda mungkin mempunyai data yang tidak konsisten jika anda menanyakan lajur baharu.

Pemulangan semula permohonan

Kini kami mempunyai versi apl 2.0.0 dan pangkalan data dalam v2.

Langkah-langkah:

  1. gulung semula aplikasi anda kepada versi 1.0.0.
  2. versi 1.0.0 tidak menggunakan lajur dalam pangkalan data surname, jadi pemulangan harus berjaya

Perubahan DB

Pangkalan data mengandungi lajur bernama 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 skrip surname.

Perhatian. Ingat bahawa anda TIDAK BOLEH MENAMBAH sebarang kekangan NOT NULL pada lajur yang anda tambahkan. Jika anda memutar balik JAR, versi lama tidak akan tahu tentang lajur yang ditambahkan dan akan secara automatik menetapkannya kepada NULL. Sekiranya terdapat had sedemikian, aplikasi lama akan pecah.

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

Perubahan kod

Kami menyimpan data sebagai last_name, dan dalam surname. Pada masa yang sama kita membaca dari last_name, memandangkan lajur ini adalah yang paling berkaitan. Semasa proses penempatan, beberapa permintaan mungkin telah diproses oleh tika aplikasi yang masih belum dikemas kini.

/*
 * 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: Mengalih keluar last_name daripada kod

Versi aplikasi: 3.0.0

Versi DB:v3

Komen

Catatan per.: Nampaknya, dalam artikel asal penulis tersilap menyalin teks blok ini dari langkah 2. Pada langkah ini, perubahan harus dibuat dalam kod aplikasi yang bertujuan untuk mengalih keluar fungsi yang menggunakan lajur last_name.

Dengan menambah lajur baharu dan menyalin kandungannya, kami mencipta perubahan pangkalan data yang serasi ke belakang. Selain itu, jika kita memutar balik JAR atau menjalankan JAR lama, ia tidak akan pecah semasa pelaksanaan.

Pemulangan semula permohonan

Pada masa ini kami mempunyai versi apl 3.0.0 dan pangkalan data v3. Versi 3.0.0 tidak menyimpan data ke last_name. Ini bermakna bahawa dalam surname maklumat yang paling terkini disimpan.

Langkah-langkah:

  1. gulung semula aplikasi anda kepada versi 2.0.0.
  2. versi 2.0.0 kegunaan dan last_name и surname.
  3. versi 2.0.0 akan mengambil surname, jika ia bukan sifar, sebaliknya -last_name

Perubahan pangkalan data

Tiada perubahan struktur dalam pangkalan data. Skrip berikut dilaksanakan untuk melakukan pemindahan terakhir data lama:

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

Perubahan kod

Catatan per.: Penerangan blok ini juga telah tersilap disalin oleh pengarang dari langkah 2. Selaras dengan logik artikel, perubahan dalam kod pada langkah ini harus bertujuan untuk mengalih keluar daripadanya unsur-unsur yang berfungsi dengan lajur last_name.

Kami menyimpan data sebagai last_name, dan dalam surname. Selain itu, kami membaca dari lajur last_name, kerana ia adalah yang paling relevan. Semasa proses penempatan, beberapa permintaan mungkin diproses oleh tika yang masih belum dinaik taraf.

/*
 * 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: Mengalih keluar last_name daripada pangkalan data

Versi aplikasi: 4.0.0

Versi DB: v4

Komen

Kerana hakikat bahawa kod versi 3.0.0 tidak menggunakan lajur last_name, tiada perkara buruk akan berlaku semasa pelaksanaan jika kita kembali ke 3.0.0 selepas mengalih keluar lajur daripada pangkalan data.

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

Perubahan DB

Relatif v3 kami hanya mengalih keluar lajur last_name dan tambah sekatan yang tiada.

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

Perubahan kod

Tiada perubahan pada kod.

Output

Kami berjaya menggunakan perubahan nama lajur yang tidak serasi ke belakang dengan melakukan beberapa penempatan yang serasi ke belakang. Di bawah ialah ringkasan tindakan yang dilakukan:

  1. penggunaan versi aplikasi 1.0.0 с v1 skema pangkalan data (nama lajur = last_name)
  2. penggunaan versi aplikasi 2.0.0, yang menyimpan data dalam last_name и surname. Permohonan dibaca dari last_name. Pangkalan data adalah dalam versi v2mengandungi lajur seperti last_nameDan surname. surname ialah salinan last_name. (NOTA: lajur ini tidak boleh mempunyai kekangan bukan nol)
  3. penggunaan versi aplikasi 3.0.0, yang hanya menyimpan data dalam surname dan dibaca daripada nama keluarga. Bagi pangkalan data, migrasi terakhir sedang berlaku last_name в surname. Juga batasan BUKAN NULL dikeluarkan daripada last_name. Pangkalan data kini dalam versi v3
  4. penggunaan versi aplikasi 4.0.0 - tiada perubahan dibuat pada kod. Penggunaan pangkalan data v4, yang mengeluarkan last_name. Di sini anda boleh menambah sebarang kekangan yang hilang pada pangkalan data.

Dengan mengikuti pendekatan ini, anda sentiasa boleh melancarkan satu versi tanpa memecahkan keserasian pangkalan data/aplikasi.

Kod

Semua kod yang digunakan dalam artikel ini boleh didapati di Github. Di bawah ialah penerangan tambahan.

Projek-projek

Selepas mengklonkan repositori, anda akan melihat struktur folder berikut.

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

Skrip

Anda boleh menjalankan skrip yang diterangkan dalam skrip di bawah, yang akan menunjukkan perubahan yang serasi ke belakang dan tidak serasi pada pangkalan data.

Untuk melihat kes dengan perubahan serasi ke belakang, jalankan:

./scripts/scenario_backward_compatible.sh

Dan untuk melihat kes dengan perubahan yang tidak serasi ke belakang, jalankan:

./scripts/scenario_backward_incompatible.sh

Laluan Terbang Contoh But Spring

Semua contoh diambil dari Spring Boot Sample Flyway.

Anda boleh lihat http://localhost:8080/flyway, terdapat senarai skrip.

Contoh ini juga termasuk konsol H2 (at http://localhost:8080/h2-console) supaya anda boleh melihat status pangkalan data (URL jdbc lalai ialah jdbc:h2:mem:testdb).

tambahan

Baca juga artikel lain di blog kami:

Sumber: www.habr.com

Tambah komen