Sıfır Kesinti Süresi Dağıtımı ve Veritabanları

Sıfır Kesinti Süresi Dağıtımı ve Veritabanları

Bu makalede, dağıtım sırasında veritabanı uyumluluk sorunlarının nasıl çözüleceği ayrıntılı olarak açıklanmaktadır. Ön hazırlık yapmadan dağıtım yapmaya çalışırsanız üretim uygulamalarınıza neler olabileceğini size anlatacağız. Daha sonra sıfır kesinti süresine sahip olmak için gereken uygulama yaşam döngüsü aşamalarını geçeceğiz (yaklaşık. şerit: daha fazla - sıfır aksama süresi). İşlemlerimizin sonucu geriye dönük uyumsuz veritabanı değişikliğinin geriye dönük uyumlu şekilde uygulanması olacaktır.

Makaledeki kod örneklerini anlamak istiyorsanız şu adreste bulabilirsiniz: GitHub.

Giriş

Sıfır kesinti süreli dağıtım

Ne mistik sıfır kesinti süresi dağıtımı? Bunun, uygulamanızın, uygulamanın yeni bir sürümünü üretime başarıyla tanıtabileceğiniz ve kullanıcı bu sürümün kullanılamadığını fark etmeyecek şekilde dağıtıldığı zaman olduğunu söyleyebilirsiniz. Kullanıcı ve şirket açısından bakıldığında bu, mümkün olan en iyi dağıtım senaryosudur çünkü yeni özelliklerin tanıtılmasına ve hataların kesintisiz olarak düzeltilmesine olanak tanır.

Bu nasıl başarılır? Birkaç yol var, işte onlardan biri:

  • hizmetinizin 1 numaralı sürümünü dağıtın
  • veritabanı geçişi gerçekleştirme
  • Hizmetinizin 2. sürümünü 1. sürüme paralel olarak dağıtın
  • 2 numaralı sürümün olması gerektiği gibi çalıştığını gördüğünüz anda 1 numaralı sürümü kaldırın
  • hazır!

Kolay değil mi? Ne yazık ki bu o kadar basit değil ve buna daha sonra ayrıntılı olarak bakacağız. Şimdi oldukça yaygın olan başka bir dağıtım sürecini kontrol edelim: mavi yeşil dağıtım.

Hiç duydun mu mavi yeşil dağıtım? Cloud Foundry bunu son derece kolaylaştırıyor. Sadece bak Bu makalede, bunu daha ayrıntılı olarak açıklayacağız. Kısaca özetlemek gerekirse mavi yeşil dağıtımın nasıl yapılacağını hatırlatalım:

  • üretim kodunuzun iki kopyasının (“mavi” ve “yeşil”) çalıştığından emin olun;
  • tüm trafiği mavi ortama yönlendirin, yani. böylece üretim URL'leri burayı işaret eder;
  • tüm uygulama değişikliklerini yeşil bir ortamda dağıtın ve test edin;
  • URL'leri maviden yeşil ortama değiştir

Mavi yeşil dağıtım, üretimin kesintiye uğramasından endişe etmeden yeni özellikleri kolayca tanıtmanıza olanak tanıyan bir yaklaşımdır. Bunun nedeni, bir şey olsa bile, yalnızca "bir düğmeye basarak" önceki ortama kolayca geri dönebilmenizdir.

Yukarıdakilerin hepsini okuduktan sonra şu soruyu sorabilirsiniz: Sıfır kesinti süresinin Mavi yeşil dağıtımla ne ilgisi var?

Pek çok ortak noktaları var, çünkü aynı ortamın iki kopyasını korumak, onları korumak için iki kat çaba gerektiriyor. Bu yüzden bazı takımlar iddia ediyor Martin Fowler, bu yaklaşımın bir varyasyonunu izleyin:

Diğer bir seçenek de aynı veritabanını kullanarak web ve etki alanı katmanları için mavi-yeşil anahtarlar oluşturmaktır. Bu yaklaşımda, özellikle yazılımın yeni bir sürümünü desteklemek için şemasını değiştirmeniz gerektiğinde, veritabanı genellikle bir sorun olabilir.

Ve işte bu yazıdaki asıl soruna geliyoruz. veritabanı. Bu ifadeye bir kez daha bakalım.

veritabanı geçişi gerçekleştirin.

Şimdi kendinize şu soruyu sormalısınız: Ya veritabanı değişikliği geriye dönük olarak uyumlu değilse? Uygulamanın ilk sürümü bozulmayacak mı? Aslında tam da böyle olacak...

Dolayısıyla, sıfır kesinti süresi/mavi yeşil dağıtımın büyük faydalarına rağmen şirketler, uygulamalarını dağıtmak için aşağıdaki daha güvenli süreci izleme eğilimindedir:

  • uygulamanın yeni sürümünü içeren bir paket hazırlayın
  • çalışan bir uygulamayı kapatma
  • veritabanını taşımak için komut dosyalarını çalıştırın
  • uygulamanın yeni bir sürümünü dağıtın ve başlatın

Bu makalede, sıfır kesinti süresi dağıtımından yararlanmak için veritabanınız ve kodunuzla nasıl çalışabileceğinizi ayrıntılarıyla anlatacağız.

Veritabanı sorunları

Veritabanında herhangi bir veri depolamayan durum bilgisi olmayan bir uygulamanız varsa, sıfır kesinti süresine sahip dağıtıma hemen sahip olabilirsiniz. Ne yazık ki çoğu yazılımın verileri bir yerde saklaması gerekiyor. Bu nedenle devrede herhangi bir değişiklik yapmadan önce iki kez düşünmelisiniz. Kesintisiz dağıtım mümkün olacak şekilde şemayı nasıl değiştireceğimizin ayrıntılarına girmeden önce, sürüm oluşturma şemasına odaklanalım.

Sürüm oluşturma şeması

Bu yazıda kullanacağımız Uçuş yolu sürüm kontrol aracı olarak (yaklaşık. Çeviri: veritabanı geçişlerinden bahsediyoruz). Doğal olarak yerleşik Flyway desteğine sahip ve uygulama bağlamını ayarlarken şema geçişini gerçekleştirecek bir Spring Boot uygulaması da yazacağız. Flyway'i kullanırken geçiş komut dosyalarını projeler klasörünüzde (varsayılan olarak classpath:db/migration). Burada bu tür geçiş dosyalarının bir örneğini görebilirsiniz

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

Bu örnekte, daha önce yürütülmemişse uygulama başlatıldığında arka arkaya yürütülecek 4 geçiş komut dosyasını görüyoruz. Dosyalardan birine bakalım (V1__init.sql) Örnek olarak.

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Her şey gayet açıklayıcıdır: Veritabanınızın nasıl değiştirilmesi gerektiğini tanımlamak için SQL'i kullanabilirsiniz. Spring Boot ve Flyway hakkında daha fazla bilgi için göz atın Spring Boot Belgeleri.

Spring Boot ile bir kaynak kontrol aracı kullanarak 2 büyük avantaj elde edersiniz:

  • veritabanı değişikliklerini kod değişikliklerinden ayırırsınız
  • Veritabanı geçişi, uygulamanızın kullanıma sunulmasıyla birlikte gerçekleşir; dağıtım süreciniz basitleştirildi

Veritabanı sorunlarını giderme

Makalenin bir sonraki bölümünde veritabanı değişikliklerine yönelik iki yaklaşıma odaklanacağız.

  • geriye dönük uyumsuzluk
  • geriye dönük uyumluluk

Birincisi, ön hazırlık yapmadan sıfır kesinti süreli dağıtım yapmamanız gerektiğine dair bir uyarı olarak değerlendirilecektir... İkincisi, kesinti olmadan dağıtım gerçekleştirirken aynı zamanda geriye dönük uyumluluğu nasıl koruyabileceğiniz konusunda bir çözüm sunuyor.

Üzerinde çalışacağımız projemiz basit bir Spring Boot Flyway uygulaması olacaktır. Person с first_name и last_name veritabanında (yaklaşık. tercüme: Person bir masa ve first_name и last_name - bunlar içindeki alanlar). Yeniden adlandırmak istiyoruz last_name в surname.

varsayımlar

Ayrıntılara girmeden önce uygulamalarımızla ilgili yapmamız gereken birkaç varsayım var. Ulaşmak istediğimiz asıl sonuç oldukça basit bir süreç olacaktır.

Not. İş PRO-İPUCU. Süreçleri basitleştirmek, destek konusunda size çok fazla para kazandırabilir (şirketinizde ne kadar çok kişi çalışırsa, o kadar çok tasarruf edebilirsiniz)!

Veritabanını geri almaya gerek yok

Bu, dağıtım sürecini basitleştirir (silme işlemini geri alma gibi bazı veritabanı geri alma işlemleri neredeyse imkansızdır). Yalnızca uygulamaları geri almayı tercih ediyoruz. Bu şekilde, farklı veritabanlarınız olsa bile (örneğin, SQL ve NoSQL), dağıtım hattınız aynı görünecektir.

Uygulamayı bir sürüm geri almak HER ZAMAN mümkün olmalıdır (artık değil)

Geri alma yalnızca gerekli olduğunda yapılmalıdır. Mevcut sürümde kolayca düzeltilemeyen bir hata varsa, en son çalışan sürüme geri dönebilmeliyiz. Bu en son çalışan sürümün bir önceki sürüm olduğunu varsayıyoruz. Birden fazla kullanıma sunma için kod ve veritabanı uyumluluğunu sürdürmek son derece zor ve pahalı olacaktır.

Dikkat. Daha iyi okunabilirlik için bu makalede uygulamanın ana sürümünü değiştireceğiz.

Adım 1: Başlangıç ​​Durumu

Uygulama sürümü: 1.0.0
Veritabanı sürümü: v1

Yorumlamak

Bu, uygulamanın başlangıç ​​durumu olacaktır.

Veritabanı değişiklikleri

Veritabanı şunları içerir: last_name.

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Kod değişiklikleri

Uygulama Kişi verilerini saklar 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
                + "]";
    }
}

Geriye doğru uyumsuz sütun yeniden adlandırma

Sütun adının nasıl değiştirileceğine ilişkin bir örneğe bakalım:

Uyarı. Aşağıdaki örnek kasıtlı olarak işleri bozacaktır. Bunu veritabanı uyumluluğu sorununu göstermek için gösteriyoruz.

Uygulama sürümü: 2.0.0.BAD

Veritabanı sürümü: v2bad

Yorumlamak

Mevcut değişiklikler aynı anda iki örneği (eski ve yeni) çalıştırmamıza izin VERMEZ. Bu nedenle, sıfır kesinti süreli dağıtıma ulaşmak zor olacaktır (eğer varsayımlar dikkate alınırsa, aslında imkansızdır).

A/B testi

Mevcut durum şu ki bir uygulama versiyonumuz var 1.0.0, üretimde ve veritabanında dağıtılan v1. Uygulamanın ikinci bir örneğini (sürüm) dağıtmamız gerekiyor. 2.0.0.BADve veritabanını güncelleyin v2bad.

adımlar:

  1. sürüm uygulamasının yeni bir örneği dağıtıldı 2.0.0.BADveritabanını güncelleyen v2bad
  2. veritabanında v2bad kolon last_name artık mevcut değil - olarak değiştirildi surname
  3. Veritabanı ve uygulama güncellemesi başarılı oldu ve bazı örnekler çalışıyor 1.0.0, diğerleri - içinde 2.0.0.BAD. Her şey veritabanına bağlı v2bad
  4. sürümün tüm örnekleri 1.0.0 sütuna veri eklemeye çalışacakları için hata atmaya başlayacaklar last_nameartık var olmayan
  5. sürümün tüm örnekleri 2.0.0.BAD sorunsuz çalışacak

Gördüğünüz gibi veritabanında ve uygulamada geriye dönük uyumsuz değişiklikler yaparsak A/B testi yapılamaz.

Uygulamayı geri alma

A/B dağıtımını yapmaya çalıştıktan sonra (yaklaşık. per.: yazar muhtemelen burada A/B testini kastetmişti) uygulamayı sürüme geri almamız gerektiğine karar verdik 1.0.0. Veritabanını geri almak istemediğimizi varsayalım.

adımlar:

  1. sürüm uygulaması örneğini durduruyoruz 2.0.0.BAD
  2. veritabanı hala v2bad
  3. versiyondan beri 1.0.0 ne olduğunu anlamıyor surname, hataları göreceğiz
  4. Cehennem çözüldü, artık geri dönemeyiz

Gördüğünüz gibi veritabanında ve uygulamada geriye dönük uyumsuz değişiklikler yaparsak önceki sürüme geri dönemeyiz.

Komut dosyası yürütme günlükleri

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

Veritabanı değişiklikleri

Yeniden adlandıran taşıma komut dosyası last_name в surname

Kaynak Flyway betiği:

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

Yeniden adlandıran komut dosyası last_name.

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

Kod değişiklikleri

Alan adını değiştirdik lastName üzerinde surname.

Bir sütunu geriye dönük olarak uyumlu bir şekilde yeniden adlandırma

En sık karşılaşabileceğimiz durum budur. Geriye doğru uyumsuz değişiklikler yapmamız gerekiyor. Sıfır kesinti süreli dağıtım için, ek adımlar olmadan veritabanı geçişini uygulamamamız gerektiğini zaten kanıtladık. Makalenin bu bölümünde, geriye dönük uyumluluğu korurken istenen sonucu elde etmek için veritabanı geçişleriyle birlikte uygulamanın 3 dağıtımını gerçekleştireceğiz.

Not. Bir sürüm veritabanımız olduğunu hatırlayın v1. Sütunlar içerir first_name и last_name. Değişmek zorundayız last_name üzerinde surname. Ayrıca uygulama sürümümüz de var 1.0.0, henüz kullanılmamış olan surname.

2. Adım: Soyadını ekleyin

Uygulama sürümü: 2.0.0
Veritabanı sürümü: v2

Yorumlamak

Yeni bir sütun ekleyip içeriğini kopyalayarak geriye dönük uyumlu veritabanı değişiklikleri oluşturuyoruz. Aynı zamanda, JAR'ı geri alırsak veya eski bir JAR'ı çalıştırırsak, yürütme sırasında bozulmayacaktır.

Yeni bir sürümü kullanıma sunuyoruz

adımlar:

  1. yeni bir sütun oluşturmak için veritabanı geçişi gerçekleştirin surname. Artık DB sürümünüz v2
  2. verileri şuradan kopyala: last_name в surname. DikkatBu verilerden çok fazlasına sahipseniz toplu geçişi düşünmelisiniz!
  3. kodu kullanıldıkları yere yazın İKİ и yenive eski kolon. Artık uygulama sürümünüz 2.0.0
  4. sütundaki değeri oku surname, ya değilse null, veya l'denast_nameyılanbalığı surname belirtilmemiş. Silebilirsin getLastName() koddan çıktı alacağı için null başvurunuzu geri alırken 3.0.0 karşı 2.0.0.

Spring Boot Flyway kullanıyorsanız bu iki adım sürüm başlatılırken gerçekleştirilecektir. 2.0.0 uygulamalar. Veritabanı sürüm oluşturma aracını manuel olarak çalıştırırsanız, bunu yapmak için iki farklı şey yapmanız gerekecektir (öncelikle veritabanı sürümünü manuel olarak güncelleyin ve ardından yeni uygulamayı dağıtın).

Önemli. Yeni oluşturulan sütunun YAPMAYIN olmak GEÇERSİZ DEĞİL. Geri alma işlemi yaparsanız eski uygulamanın yeni sütundan haberi olmaz ve geri alma işlemi sırasında onu yüklemez. Insert. Ancak bu kısıtlamayı eklerseniz db'niz v2, bu yeni sütunun değerinin ayarlanmasını gerektirecektir. Bu da kısıtlamaların ihlaline yol açacaktır.

Önemli. Yöntemi kaldırmalısınız getLastName(), çünkü sürümde 3.0.0 Kodda sütun kavramı yok last_name. Bu, orada null değerinin ayarlanacağı anlamına gelir. Yöntemden ayrılabilir ve kontroller ekleyebilirsiniz. null, ancak çok daha iyi bir çözüm mantıkta olduğundan emin olmak olacaktır. getSurname() sıfır olmayan doğru değeri seçtiniz.

A/B testi

Mevcut durum şu ki bir uygulama versiyonumuz var 1.0.0, üretimde dağıtılan ve veritabanındaki v1. Sürüm uygulamasının ikinci bir örneğini dağıtmamız gerekiyor 2.0.0veritabanını güncelleyecek v2.

adımlar:

  1. sürüm uygulamasının yeni bir örneği dağıtıldı 2.0.0veritabanını güncelleyen v2
  2. bu arada bazı istekler sürüm örnekleri tarafından işlendi 1.0.0
  3. güncelleme başarılı oldu ve sürüm uygulamasının birden fazla çalışan örneğine sahipsiniz 1.0.0 ve diğer versiyonlar 2.0.0. Herkes veritabanıyla iletişim kurar v2
  4. versiyon 1.0.0 veritabanındaki soyadı sütununu kullanmaz, ancak sürüm 2.0.0 kullanır. Birbirlerine müdahale etmezler ve hiçbir hata olmamalıdır.
  5. versiyon 2.0.0 verileri hem eski hem de yeni sütunda saklayarak geriye dönük uyumluluk sağlar

Önemli. Öğeleri eski/yeni sütundaki değerlere göre sayan herhangi bir sorgunuz varsa, artık yinelenen değerleriniz olduğunu (büyük olasılıkla hâlâ taşınıyor olduklarını) unutmamalısınız. Örneğin, soyadı (sütun adı ne olursa olsun) şu harfle başlayan kullanıcıların sayısını saymak istiyorsanız A, ardından veri geçişi tamamlanana kadar (oldnew sütun) yeni bir sütunu sorgularsanız tutarsız verileriniz olabilir.

Uygulamayı geri alma

Artık uygulama sürümümüz var 2.0.0 ve veritabanındaki v2.

adımlar:

  1. uygulamanızı sürüme geri alın 1.0.0.
  2. versiyon 1.0.0 veritabanındaki bir sütunu kullanmaz surname, yani geri alma başarılı olmalı

Veritabanı değişiklikleri

Veritabanı adında bir sütun içeriyor last_name.

Flyway kaynak komut dosyası:

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

Komut dosyası ekle surname.

Uyarı. Eklediğiniz sütuna herhangi bir NOT NULL kısıtlaması EKLEYEMEYECEĞİNİZİ unutmayın. JAR'ı geri alırsanız eski sürümün eklenen sütun hakkında hiçbir fikri olmayacak ve onu otomatik olarak NULL olarak ayarlayacaktır. Böyle bir sınırlama varsa eski uygulama tamamen bozulacaktır.

-- NOTE: This field can't have the NOT NULL constraint cause if you rollback, the old version won't know about this field
-- and will always set it to NULL
ALTER TABLE PERSON ADD surname varchar(255);

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Kod değişiklikleri

Verileri şu şekilde saklıyoruz: last_nameve surname. Aynı zamanda okuduğumuz last_name, çünkü bu sütun en alakalı olanıdır. Dağıtım işlemi sırasında bazı istekler henüz güncellenmemiş bir uygulama örneği tarafından işlenmiş olabilir.

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

3. Adım: Last_name'in koddan kaldırılması

Uygulama sürümü: 3.0.0

Veritabanı sürümü:v3

Yorumlamak

Not per.: Görünüşe göre, orijinal makalede yazar yanlışlıkla 2. adımdaki bu bloğun metnini kopyaladı. Bu adımda, sütunu kullanan işlevselliği kaldırmayı amaçlayan uygulama kodunda değişiklikler yapılmalıdır. last_name.

Yeni bir sütun ekleyip içeriğini kopyalayarak geriye dönük uyumlu veritabanı değişiklikleri oluşturduk. Ayrıca, JAR'ı geri alırsak veya eski bir JAR'ı çalıştırırsak, yürütme sırasında bozulmayacaktır.

Uygulamayı geri alma

Şu anda uygulama sürümümüz var 3.0.0 ve veritabanı v3. Sürüm 3.0.0 verileri şuraya kaydetmez: last_name. Bu şu anlama gelir: surname en güncel bilgiler saklanır.

adımlar:

  1. uygulamanızı sürüme geri alın 2.0.0.
  2. versiyon 2.0.0 kullanır ve last_name и surname.
  3. versiyon 2.0.0 alacak surname, eğer sıfır değilse, aksi takdirde -last_name

Veritabanı değişiklikleri

Veritabanında yapısal bir değişiklik yoktur. Eski verilerin son geçişini gerçekleştirmek için aşağıdaki komut dosyası yürütülür:

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
-- ALSO WE'RE NOT CHECKING IF WE'RE NOT OVERRIDING EXISTING ENTRIES. WE WOULD HAVE TO COMPARE
-- ENTRY VERSIONS TO ENSURE THAT IF THERE IS ALREADY AN ENTRY WITH A HIGHER VERSION NUMBER
-- WE WILL NOT OVERRIDE IT.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;

-- DROPPING THE NOT NULL CONSTRAINT; OTHERWISE YOU WILL TRY TO INSERT NULL VALUE OF THE LAST_NAME
-- WITH A NOT_NULL CONSTRAINT.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;

Kod değişiklikleri

Not per.: Bu bloğun açıklaması da yazar tarafından 2. adımdan yanlışlıkla kopyalanmıştır. Makalenin mantığına uygun olarak, bu adımdaki kodda yapılacak değişiklikler, sütunla çalışan öğelerin bloktan kaldırılmasını amaçlamalıdır. last_name.

Verileri şu şekilde saklıyoruz: last_nameve surname. Ek olarak, sütundan okuyoruz last_nameçünkü en alakalı olanıdır. Dağıtım işlemi sırasında bazı istekler henüz yükseltilmemiş bir örnek tarafından işlenebilir.

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

Adım 4: Soyadı veritabanından kaldırılıyor

Uygulama sürümü: 4.0.0

Veritabanı sürümü: v4

Yorumlamak

Sürüm kodunun olması nedeniyle 3.0.0 sütunu kullanmadım last_namegeri dönersek yürütme sırasında kötü bir şey olmayacak 3.0.0 veritabanından bir sütunu kaldırdıktan sonra.

Komut dosyası yürütme günlükleri

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

Veritabanı değişiklikleri

Hakkında v3 sadece sütunu kaldırıyoruz last_name ve eksik kısıtlamaları ekleyin.

-- REMOVE THE COLUMN
ALTER TABLE PERSON DROP last_name;

-- ADD CONSTRAINTS
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Kod değişiklikleri

Kodda herhangi bir değişiklik yok.

Aviator apk

Geriye dönük olarak uyumlu birkaç dağıtım gerçekleştirerek, geriye dönük olarak uyumsuz bir sütun adı değişikliğini başarıyla uyguladık. Aşağıda gerçekleştirilen eylemlerin bir özeti yer almaktadır:

  1. uygulama sürümünün dağıtımı 1.0.0 с v1 veritabanı şeması (sütun adı = last_name)
  2. uygulama sürümünün dağıtımı 2.0.0, verileri depolayan last_name и surname. Uygulama şunu okur: last_name. Veritabanı sürümde v2gibi sütunlar içeren last_nameVe surname. surname l'in bir kopyasıast_name. (NOT: Bu sütunun boş olmayan bir kısıtlaması olmamalıdır)
  3. uygulama sürümünün dağıtımı 3.0.0, yalnızca verileri depolayan surname ve soyadından okur. Veritabanına gelince, son geçiş gerçekleşiyor last_name в surname. Ayrıca bir sınırlama GEÇERSİZ DEĞİL çekilmekten last_name. Veritabanı artık sürümde v3
  4. uygulama sürümünün dağıtımı 4.0.0 - kodda herhangi bir değişiklik yapılmaz. Veritabanı dağıtımı v4, kaldıran last_name. Burada eksik olan kısıtlamaları veritabanına ekleyebilirsiniz.

Bu yaklaşımı izleyerek, veritabanı/uygulama uyumluluğunu bozmadan her zaman bir sürümü geri alabilirsiniz.

Kod

Bu makalede kullanılan tüm kodlara şuradan ulaşılabilir: Github. Aşağıda ek açıklama bulunmaktadır.

Projeler

Depoyu klonladıktan sonra aşağıdaki klasör yapısını göreceksiniz.

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

Veritabanında geriye dönük uyumlu ve uyumsuz değişiklikleri gösterecek olan aşağıdaki scriptlerde anlatılan scriptleri çalıştırabilirsiniz.

Görmek geriye doğru uyumlu değişikliklerin olduğu durum, koşmak:

./scripts/scenario_backward_compatible.sh

Ve görmek geriye doğru uyumsuz değişikliklerin olduğu durum, koşmak:

./scripts/scenario_backward_incompatible.sh

Spring Boot Örnek Geçiş Yolu

Tüm örnekler şuradan alınmıştır: Spring Boot Sample Flyway.

Şuna bir göz atabilirsin http://localhost:8080/flyway, komut dosyalarının bir listesi var.

Bu örnek aynı zamanda H2 konsolunu da içerir ( http://localhost:8080/h2-console) böylece veritabanı durumunu görüntüleyebilirsiniz (varsayılan jdbc URL'si: jdbc:h2:mem:testdb).

ayrıca

Ayrıca blogumuzdaki diğer makaleleri de okuyun:

Kaynak: habr.com

Yorum ekle