Penerapan dan Basis Data Downtime Nol

gambar


Artikel ini menjelaskan secara rinci cara mengatasi masalah yang terkait dengan kompatibilitas database selama penerapan. Kami akan memberi tahu Anda apa yang dapat terjadi pada aplikasi Anda di prod jika Anda mencoba melakukan penempatan tanpa persiapan awal. Kemudian kita akan melalui tahapan siklus hidup aplikasi, yang diperlukan untuk memiliki nol downtime ( kira-kira Terjemahkan.: Lebih lanjut - nol downtime ). Hasil dari operasi kami akan menjadi aplikasi dari perubahan basis data yang tidak kompatibel ke belakang dengan cara yang kompatibel ke belakang.


Jika Anda ingin memahami contoh kode dari artikel, Anda akan menemukannya di GitHub .


Pendahuluan


Penerapan downtime nol


Apakah penyebaran nol downtime mistis? Kami dapat mengatakan ini ketika aplikasi Anda dikerahkan sehingga Anda dapat berhasil memperkenalkan versi baru aplikasi untuk produksi, sementara pengguna tidak melihat tidak dapat diaksesnya nya. Dari sudut pandang pengguna dan perusahaan, ini adalah skenario penempatan terbaik, karena dengan cara ini Anda dapat memperkenalkan fungsi baru dan menghilangkan kesalahan tanpa gangguan.


Bagaimana cara mencapai ini? Ada beberapa cara, berikut ini salah satunya:


  • perluas versi 1 layanan Anda
  • bermigrasi database
  • gunakan versi 2 layanan Anda secara paralel dengan versi 1
  • segera setelah Anda melihat bahwa versi nomor 2 berfungsi sebagaimana mestinya, hapus versi nomor 1
  • selesai!

Mudah kan? Sayangnya, ini tidak begitu sederhana, dan kami akan mempertimbangkan ini secara rinci nanti. Sekarang mari kita periksa proses penyebaran lain yang cukup umum - penyebaran hijau biru.


Pernahkah Anda mendengar penyebaran biru hijau ? Dengan Cloud Foundry, ini sangat mudah dilakukan. Lihat saja artikel ini di mana kami menggambarkannya dengan lebih detail. Meringkas secara singkat, kita ingat bagaimana melakukan penyebaran biru hijau:


  • Pastikan pengoperasian dua salinan kode produksi Anda ("biru" dan "hijau");
  • mengarahkan semua lalu lintas ke lingkungan biru, mis. sehingga URL produksi diarahkan ke sana;
  • Menyebarkan dan menguji semua perubahan aplikasi dalam lingkungan hijau
  • alihkan url dari lingkungan biru ke hijau

Penyebaran hijau biru adalah pendekatan yang memungkinkan Anda untuk dengan mudah memperkenalkan fitur-fitur baru tanpa khawatir bahwa produksi akan rusak. Ini disebabkan oleh fakta bahwa bahkan jika sesuatu terjadi, Anda dapat dengan mudah memutar kembali ke lingkungan sebelumnya hanya dengan "mengklik sebuah saklar".


Setelah membaca semua hal di atas, Anda dapat mengajukan pertanyaan: Apa yang tidak ada hubungannya dengan downtime hijau dengan penyebaran Biru hijau?


Yah, mereka memiliki banyak kesamaan, karena mendukung dua salinan dari lingkungan yang sama memerlukan upaya ganda untuk mempertahankannya. Inilah sebabnya mengapa beberapa tim, menurut Martin Fowler , mematuhi variasi pada pendekatan ini:


Pilihan lain adalah menggunakan basis data yang sama, membuat sakelar biru-hijau untuk lapisan web dan domain. Dalam pendekatan ini, basis data seringkali menjadi masalah, terutama ketika Anda perlu mengubah skema untuk mendukung versi baru perangkat lunak.


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


bermigrasi database.


Sekarang Anda harus bertanya pada diri sendiri pertanyaan - bagaimana jika mengubah basis data tidak kompatibel? Apakah versi aplikasi saya yang pertama tidak akan rusak? Bahkan, inilah yang akan terjadi ...


Dengan demikian, meskipun ada manfaat besar dari penerapan downtime / blue green nol, perusahaan cenderung mengikuti proses penyebaran yang lebih aman berikut untuk aplikasi mereka:


  • menyiapkan paket dengan versi aplikasi yang baru
  • mematikan aplikasi yang sedang berjalan
  • jalankan skrip untuk migrasi basis data
  • menyebarkan dan meluncurkan versi baru aplikasi

Pada artikel ini, kami akan menjelaskan secara rinci bagaimana Anda dapat bekerja dengan database dan kode untuk memanfaatkan penerapan downtime nol.


Masalah Basis Data


Jika Anda memiliki aplikasi tanpa kewarganegaraan yang tidak menyimpan data apa pun dalam database, Anda bisa mendapatkan penerapan downtime nol segera. Sayangnya, sebagian besar perangkat lunak perlu menyimpan data di suatu tempat. Inilah sebabnya mengapa Anda harus berpikir dua kali sebelum melakukan perubahan pada sirkuit. Sebelum kita mempelajari detail cara mengubah skema sehingga menjadi mungkin untuk digunakan tanpa downtime, mari kita fokus dulu pada skema kontrol versi.


Skema kontrol versi


Pada artikel ini, kami akan menggunakan Flyway sebagai alat untuk kontrol versi ( kira-kira. Terjemahan: kita berbicara tentang migrasi basis data ). Secara alami, kami juga akan menulis aplikasi Spring Boot yang memiliki dukungan Flyway bawaan dan akan memigrasikan rangkaian saat menyiapkan konteks aplikasi. Saat menggunakan Flyway, Anda dapat menyimpan skrip migrasi di folder proyek Anda (secara default di classpath:db/migration ). Di sini Anda dapat melihat contoh file migrasi tersebut.


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

Dalam contoh ini, kita melihat 4 skenario migrasi yang, jika mereka tidak dieksekusi lebih awal, akan dieksekusi satu demi satu ketika aplikasi dimulai. Mari kita lihat salah satu file ( 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'); 

Semuanya berbicara dengan sempurna untuk dirinya sendiri: Anda dapat menggunakan SQL untuk menentukan bagaimana database Anda harus dimodifikasi. Untuk informasi lebih lanjut tentang Spring Boot dan Flyway, lihat Spring Boot Documents .


Menggunakan kontrol versi dengan Spring Boot memberi Anda 2 manfaat besar:


  • Anda memisahkan perubahan basis data dari perubahan kode
  • migrasi basis data terjadi bersamaan dengan peluncuran aplikasi Anda, mis. proses penyebaran Anda disederhanakan

Mengatasi Masalah Basis Data


Pada bagian selanjutnya dari artikel ini, kami akan fokus pada pertimbangan dua pendekatan untuk perubahan basis data.


  • ketidakcocokan mundur
  • kompatibilitas mundur

Yang pertama akan dianggap sebagai peringatan bahwa Anda tidak boleh melakukan penerapan downtime nol tanpa persiapan awal ... Yang kedua menawarkan solusi tentang bagaimana Anda dapat melakukan penempatan tanpa downtime dan pada saat yang sama menjaga kompatibilitas mundur.


Proyek kami, yang akan kami kerjakan, akan menjadi aplikasi Spring Boot Flyway sederhana di mana ada Seseorang dengan first_name dan last_name dalam database ( sekitar: Person adalah tabel, dan f irst_name dan last_name adalah bidang di dalamnya ). Kami ingin mengganti nama last_name menjadi surname .


Asumsi


Sebelum kita mempelajari detailnya, kita perlu menjabarkan beberapa asumsi tentang aplikasi kita. Hasil utama yang ingin kita capai adalah proses yang cukup sederhana.


Catatan PRO-TIP Bisnis. Proses perampingan dapat menghemat banyak uang untuk Anda (semakin banyak orang bekerja di perusahaan Anda, semakin banyak uang yang dapat Anda hemat)!

Tidak perlu memutar kembali basis data


Ini menyederhanakan proses penyebaran (beberapa rollbacks dari database hampir mustahil, misalnya, rollback deletion). Kami lebih suka mengembalikan aplikasi saja. Dengan cara ini, bahkan jika Anda memiliki basis data yang berbeda (mis. SQL dan NoSQL), pipa penempatan Anda akan terlihat sama.


Harus SELALU dimungkinkan untuk memutar kembali aplikasi satu versi ke belakang (tidak lebih)


Kembalikan harus dilakukan hanya jika perlu. Jika ada kesalahan dalam versi saat ini yang tidak mudah untuk diperbaiki, kita harus dapat mengembalikan versi kerja terbaru. Kami menganggap bahwa versi kerja terbaru ini adalah yang sebelumnya. Mempertahankan kode dan kompatibilitas basis data untuk lebih dari satu peluncuran akan sangat sulit dan mahal.


Catatan Untuk keterbacaan yang lebih besar, dalam kerangka artikel ini kami akan mengubah versi utama aplikasi.

Langkah 1: Status Awal


Versi Aplikasi: 1.0.0
Versi DB: v1


Komentar


Ini akan menjadi kondisi awal aplikasi.


Perubahan DB


Basis data berisi 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 Kode


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

Pengubahan nama kolom tidak kompatibel


Mari kita lihat contoh cara mengubah nama kolom:


Perhatian Contoh berikut akan dengan sengaja dipatahkan. Kami menunjukkan ini untuk menunjukkan masalah kompatibilitas database.

Versi Aplikasi: 2.0.0.BAD


Versi DB: v2bad


Komentar


Perubahan saat ini TIDAK memungkinkan kami menjalankan dua instance (lama dan baru) secara bersamaan. Dengan demikian, penyebaran downtime nol akan sulit untuk dicapai (asumsi yang diperhitungkan, ini hampir tidak mungkin).


Pengujian A / B


Situasi saat ini adalah bahwa kita memiliki versi aplikasi 1.0.0, digunakan dalam prod, dan database v1 . Kita harus menggunakan instance kedua dari aplikasi, versi 2.0.0.BAD , dan memutakhirkan database ke v2bad .


Langkah-langkah:


  1. menyebarkan contoh aplikasi versi 2.0.0.BAD , yang memperbarui basis data ke v2bad
  2. kolom last_name tidak lagi ada di database v2bad - itu diubah menjadi surname
  3. Pembaruan database dan aplikasi berhasil, dan beberapa contoh berfungsi di 1.0.0 , yang lain di 2.0.0.BAD . Semua yang terkait dengan v2bad
  4. semua instance versi 1.0.0 akan mulai melempar kesalahan karena mereka akan mencoba memasukkan data ke dalam kolom last_name , yang tidak lagi
  5. semua instance versi 2.0.0.BAD akan bekerja tanpa masalah

Seperti yang Anda lihat, jika kami membuat perubahan yang tidak kompatibel ke belakang ke database dan aplikasi, pengujian A / B tidak mungkin.


Aplikasi rollback


Mari kita asumsikan bahwa setelah mencoba melakukan penyebaran A / B ( kira-kira. Terjemahan: mungkin, penulis merujuk ke pengujian A / B di sini ), kami memutuskan bahwa kami harus memutar kembali aplikasi ke versi 1.0.0. Misalkan kita tidak ingin memutar kembali basis data.


Langkah-langkah:


  1. kami menghentikan aplikasi instance versi 2.0.0.BAD
  2. basis data masih v2bad
  3. karena versi 1.0.0 tidak mengerti apa surname , kita akan melihat kesalahan
  4. Neraka bebas, kita tidak bisa lagi kembali

Seperti yang Anda lihat, jika kami membuat perubahan yang tidak kompatibel ke belakang ke database dan aplikasi, kami tidak dapat memutar kembali ke versi sebelumnya.


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

Perubahan DB


Skrip migrasi yang last_name nama last_name menjadi 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'); 

Sebuah skrip yang last_name nama last_name .


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

Perubahan Kode


Kami mengubah nama bidang nama surname ke surname .


Mengganti nama kolom dengan cara yang kompatibel mundur


Ini adalah situasi paling umum yang mungkin kita temui. Kita perlu membuat perubahan yang tidak kompatibel ke belakang. Kami telah membuktikan bahwa untuk penerapan tanpa downtime, kami tidak boleh hanya menerapkan migrasi basis data tanpa tindakan tambahan. Pada bagian artikel ini, kami akan melakukan 3 penyebaran aplikasi bersama dengan migrasi basis data untuk mencapai hasil yang diinginkan dan pada saat yang sama menjaga kompatibilitas ke belakang.


Catatan Ingatlah bahwa kita memiliki versi database v1 . Ini berisi kolom first_name dan last_name . Kita harus mengubah last_name menjadi surname . Kami juga memiliki aplikasi versi 1.0.0, yang belum menggunakan surname .

Langkah 2: tambahkan nama keluarga


Versi Aplikasi: 2.0.0
Versi DB: v2


Komentar


Dengan menambahkan kolom baru dan menyalin isinya, kami membuat perubahan basis data yang kompatibel. Pada saat yang sama, jika kita memutar kembali JAR atau kita memiliki JAR lama yang berfungsi, itu tidak akan rusak saat runtime.


Kami meluncurkan versi baru


Langkah-langkah:


  1. bermigrasi database untuk membuat kolom surname baru. Sekarang versi db v2
  2. menyalin data dari last_name ke surname . Perhatikan bahwa jika Anda memiliki banyak data ini, Anda harus mempertimbangkan migrasi kumpulan!
  3. tulis kode di mana KEDUA kolom baru dan lama digunakan. Sekarang versi aplikasi Anda 2.0.0
  4. baca nilai dari kolom surname jika bukan null , atau dari l ast_name jika surname tidak ditentukan. Anda dapat menghapus getLastName() dari kode, karena itu akan mengembalikan null ketika Anda memutar kembali aplikasi Anda dari 3.0.0 ke 2.0.0 .

Jika Anda menggunakan Spring Boot Flyway, kedua langkah ini akan dilakukan selama peluncuran versi 2.0.0 aplikasi. Jika Anda menjalankan alat pembuatan versi basis data secara manual, Anda harus melakukan dua hal yang berbeda untuk ini (pertama-tama perbarui versi db secara manual, dan kemudian gunakan aplikasi baru).


Itu penting. Ingatlah bahwa kolom yang baru dibuat TIDAK HARUS TIDAK NULL . Jika Anda mundur, aplikasi lama tidak tahu tentang kolom baru dan tidak akan menginstalnya selama Insert. Tetapi jika Anda menambahkan batasan ini, dan database Anda akan menjadi v2 , itu akan memerlukan pengaturan nilai kolom baru. Yang akan mengarah pada pelanggaran pembatasan.

Itu penting. Anda harus menghapus metode getLastName() , karena versi 3.0.0 tidak memiliki konsep kolom last_name dalam kode. Ini berarti bahwa null akan diset di sana. Anda dapat meninggalkan metode dan menambahkan cek null , tetapi solusi yang jauh lebih baik adalah memastikan bahwa dalam logika getSurname() Anda telah memilih nilai bukan nol yang benar.

Pengujian A / B


Situasi saat ini adalah bahwa kami memiliki versi aplikasi 1.0.0 digunakan pada prod dan database di v1 . Kita perlu menggunakan instance kedua dari aplikasi versi 2.0.0 , yang akan meningkatkan basis data ke v2 .


Langkah-langkah:


  1. menyebarkan contoh aplikasi versi 2.0.0 , yang memperbarui basis data ke v2
  2. sementara itu, beberapa permintaan ditangani oleh instance versi 1.0.0
  3. pembaruan berhasil, dan Anda memiliki beberapa instance aplikasi versi 1.0.0 dan sisanya versi 2.0.0. Semua orang berkomunikasi dengan database di v2
  4. versi 1.0.0 tidak menggunakan kolom nama keluarga di database, tetapi versi 2.0.0 menggunakan. Mereka tidak saling mengganggu, dan seharusnya tidak ada kesalahan.
  5. versi 2.0.0 menyimpan data di kolom lama dan baru, yang menyediakan kompatibilitas ke belakang

Itu penting. Jika Anda memiliki kueri yang menghitung item berdasarkan nilai dari kolom lama / baru, Anda harus ingat bahwa sekarang Anda memiliki nilai duplikat (kemungkinan besar mereka masih bermigrasi). Misalnya, jika Anda ingin menghitung jumlah pengguna yang nama belakangnya (tidak peduli bagaimana kolom itu disebut) dimulai dengan huruf A , maka Anda mungkin memiliki data yang tidak konsisten sebelum Anda menyelesaikan migrasi data (kolom oldnew ), jika Anda menjalankan kueri pada kolom baru.

Aplikasi rollback


Sekarang kami memiliki aplikasi versi 2.0.0 dan database di v2 .


Langkah-langkah:


  1. putar kembali aplikasi Anda ke versi 1.0.0 .
  2. versi 1.0.0 tidak menggunakan kolom surname di database, jadi kembalikan harus berhasil

Perubahan DB


Basis data berisi kolom bernama last_name .


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

Script untuk menambahkan surname .


Perhatian Ingatlah bahwa Anda TIDAK BISA MENAMBAH kendala TIDAK NULL pada kolom yang ditambahkan. Jika Anda mengembalikan JAR, versi lama tidak tahu tentang kolom yang ditambahkan, dan secara otomatis akan mengaturnya menjadi NULL. Jika ada batasan seperti itu, aplikasi lama hanya akan 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 

Perubahan Kode


Kami menyimpan data dalam last_name dan surname . Pada saat yang sama, kami membaca dari last_name , karena kolom ini paling relevan. Selama proses penyebaran, beberapa permintaan mungkin telah ditangani oleh sebuah instance aplikasi yang belum diperbarui.


 /* * 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: Menghapus nama belakang dari kode


Versi Aplikasi: 3.0.0


Versi DB: v3


Komentar


Catatan Lane: Rupanya, dalam artikel asli, penulis keliru menyalin teks dari blok ini dari langkah 2. Pada langkah ini, perubahan harus dilakukan pada kode aplikasi yang bertujuan untuk menghapus fungsionalitas yang menggunakan kolom last_name .


Dengan menambahkan kolom baru dan menyalin isinya, kami membuat perubahan basis data yang kompatibel. Juga, jika kita memutar kembali JAR atau kita memiliki JAR lama yang berfungsi, itu tidak akan rusak saat runtime.


Aplikasi rollback


Saat ini kami memiliki aplikasi versi 3.0.0 dan basis data v3 . Versi 3.0.0 tidak menyimpan data dalam last_name . Ini berarti bahwa surname menyimpan informasi terbaru.


Langkah-langkah:


  1. putar kembali aplikasi Anda ke versi 2.0.0 .
  2. versi 2.0.0 menggunakan last_name dan surname .
  3. versi 2.0.0 akan mengambil surname jika bukan nol, jika tidak surname

Perubahan DB


Tidak ada perubahan struktural dalam database. Skrip berikut dijalankan, yang melakukan migrasi terakhir dari 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 Kode


Catatan trans .: Deskripsi blok ini juga disalin secara keliru oleh penulis dari langkah 2. Sesuai dengan logika cerita artikel, perubahan kode pada langkah ini harus bertujuan untuk menghapus elemen-elemen yang bekerja dengan kolom last_name .


Kami menyimpan data dalam last_name dan surname. Selain itu, kami membaca dari kolom last_name , karena paling relevan. Selama proses penyebaran, beberapa permintaan dapat diproses dengan mesin virtual yang belum diperbarui.


 /* * 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: Menghapus nama belakang dari database


Versi Aplikasi: 4.0.0


Versi DB: v4


Komentar


Karena fakta bahwa kode versi 3.0.0 tidak menggunakan kolom last_name , tidak ada hal buruk yang akan terjadi selama eksekusi jika kita kembali ke 3.0.0 setelah menghapus kolom dari 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"} 

Perubahan DB


Untuk v3 kami cukup menghapus kolom last_name dan menambahkan batasan yang hilang.


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


Tidak ada perubahan dalam kode.


Kesimpulan


Kami berhasil menerapkan perubahan nama kolom mundur yang tidak kompatibel dengan melakukan beberapa penyebaran yang kompatibel mundur. Di bawah ini adalah ringkasan dari langkah-langkah yang diambil:


  1. penerapan versi aplikasi 1.0.0 dengan skema basis data v1 (nama kolom = nama belakang)
  2. menggunakan aplikasi versi 2.0.0, yang menyimpan data dalam last_name dan surname . Aplikasi membaca dari last_name . Basis data ada dalam versi v2 , yang berisi kolom- surname. surname dari last_name dan surname. surname surname. surname adalah salinan dari l ast_name . (: not null)
  3. 3.0.0 , surname surname. , last_name surname . NOT NULL last_name . v3
  4. 4.0.0 — . v4 , last_name . .

, , / .


Kode


, , Github . .



, .


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


, , .


, :


 ./scripts/scenario_backward_compatible.sh 

, :


 ./scripts/scenario_backward_incompatible.sh 

Spring Boot Sample Flyway


Spring Boot Sample Flyway.


http://localhost:8080/flyway , .


H2 ( http://localhost:8080/h2-console ), (URL jdbc — jdbc:h2:mem:testdb ).


Opsional



Baca juga artikel lain di blog kami:


Source: https://habr.com/ru/post/id481932/


All Articles