Нөл токтоп калуу убактысын жайылтуу жана маалымат базалары

Нөл токтоп калуу убактысын жайылтуу жана маалымат базалары

Бул макалада жайылтууда маалымат базасынын шайкештик маселелерин кантип чечүү керектиги кеңири түшүндүрүлөт. Эгер сиз алдын ала даярдыксыз жайылтууга аракет кылсаңыз, өндүрүштүк тиркемелериңиз менен эмне болушу мүмкүн экенин айтып беребиз. Андан кийин биз нөл токтоп калуу талап кылынган тиркеменин иштөө циклинин этаптарынан өтөбүз (болжол менен тилке: андан ары - нөл токтоп калуу). Биздин иш-аракеттерибиздин натыйжасы артка карай шайкеш келбеген маалымат базасын өзгөртүүнү артка кайтууга ылайыктуу түрдө колдонуу болот.

Эгер сиз макаладагы код мисалдарын түшүнгүңүз келсе, аларды бул жерден таба аласыз GitHub.

тааныштыруу

Нөл токтоп калуу

Кандай мистика нөл токтоп туруу? Колдонмонун жаңы версиясын өндүрүшкө ийгиликтүү киргизе ала тургандай кылып, колдонуучу анын жеткиликтүү эместигин байкабай тургандай кылып орнотулган деп айта аласыз. Колдонуучунун жана компаниянын көз карашынан алганда, бул мүмкүн болушунча эң мыкты жайылтуу сценарийи, анткени ал жаңы функцияларды киргизүүгө жана мүчүлүштүктөрдү үзгүлтүксүз оңдоого мүмкүндүк берет.

Буга кантип жетишсе болот? бир нече жолдору бар, бул жерде алардын бири болуп саналат:

  • кызматыңыздын №1 версиясын орнотуңуз
  • маалымат базасын көчүрүү
  • Кызматыңыздын №2 версиясын №1 версияга параллелдүү жайгаштырыңыз
  • №2 версиянын керектүүдөй иштеп жатканын көргөнүңүз менен, №1 версияны алып салыңыз
  • даяр!

Жөнөкөй, туурабы? Тилекке каршы, бул анчалык деле жөнөкөй эмес, биз муну кийинчерээк майда-чүйдөсүнө чейин карап чыгабыз. Эми дагы бир кеңири таралган жайылтуу процессин текшерип көрөлү - көк жашыл жайылтуу.

Сиз буга чейин уккан белеңиз көк жашыл жайылтуу? Cloud Foundry муну абдан жеңил кылат. Жөн эле кара бул макалада, биз муну кененирээк сүрөттөп беребиз. Кыскача жыйынтыктоо үчүн, көк жашыл жайгаштырууну кантип жасоо керектигин эскертип көрөлү:

  • өндүрүш кодуңуздун эки нускасы (“көк” жана “жашыл”) иштешин камсыз кылуу;
  • бардык трафикти көк чөйрөгө багыттоо, б.а. өндүрүш URL даректери ошол жерде көрсөтүлүшү үчүн;
  • жашыл чөйрөдө бардык тиркемелерди өзгөртүү жана сыноо;
  • url'дерди көк түстөн жашыл чөйрөгө которуу

Көк жашыл жайгаштыруу - бул өндүрүштүн бузулушуна тынчсызданбастан жаңы функцияларды оңой киргизүүгө мүмкүндүк берген ыкма. Мунун себеби, бир нерсе болуп кетсе да, жөн гана "которгучту чыкылдатуу" менен мурунку чөйрөгө оңой кайтууга болот.

Жогоруда айтылгандардын баарын окуп чыккандан кийин, сиз суроо беришиңиз мүмкүн: Көк жашыл жайгаштыруу менен нөл токтоп калуусунун кандай тиешеси бар?

Ооба, алардын көп окшоштуктары бар, анткени бир эле чөйрөнүн эки нускасын сактоо аларды сактоо үчүн эки эсе көп күч-аракетти талап кылат. Мына ушундан улам кээ бир командалар ырасташат Мартин Фаулер, бул ыкманын бир вариантын колдонуңуз:

Дагы бир вариант - ошол эле маалымат базасын колдонуу, желе жана домен катмарлары үчүн көк-жашыл өчүргүчтөрдү түзүү. Бул ыкмада маалымат базасы көбүнчө көйгөй жаратышы мүмкүн, өзгөчө программанын жаңы версиясын колдоо үчүн анын схемасын өзгөртүү керек болгондо.

Жана бул жерде биз бул макалада негизги көйгөйгө келдик. Маалымат базасы. Келгиле, бул сөз айкашын дагы бир жолу карап көрөлү.

маалымат базасын көчүрүү.

Эми сиз өзүңүзгө суроо беришиңиз керек - эгерде маалымат базасын өзгөртүү артка шайкеш келбесечи? Колдонмонун биринчи версиясы бузулбайбы? Чынында, дал ушундай болот...

Ошентип, нөлдүк токтоп калуу/көк жашыл жайгаштыруунун чоң артыкчылыктарына карабастан, компаниялар өздөрүнүн тиркемелерин жайылтуу үчүн төмөнкү коопсуз процессти карманышат:

  • колдонмонун жаңы версиясы менен пакетти даярдоо
  • иштеп жаткан колдонмону өчүрүү
  • маалымат базасын көчүрүү үчүн скрипттерди иштетүү
  • колдонмонун жаңы версиясын орнотуп, ишке киргизиңиз

Бул макалада биз өзүңүздүн маалымат базаңыз жана кодуңуз менен кантип иштесе болорун майда-чүйдөсүнө чейин айтып беребиз.

Маалыматтар базасы маселелери

Эгер сизде маалымат базасында эч кандай маалымат сакталбаган жарандыгы жок тиркеме болсо, сиз дароо нөлдүк токтоп калууга ээ боло аласыз. Тилекке каршы, көпчүлүк программалык камсыздоо маалыматтарды бир жерде сакташы керек. Ошондуктан схемага кандайдыр бир өзгөртүүлөрдү киргизүүдөн мурун эки жолу ойлонушуңуз керек. Үзгүлтүксүз жайылтуу мүмкүн болушу үчүн схеманы кантип өзгөртүү керектигинин чоо-жайына кирүүдөн мурун, келгиле, адегенде версиялоо схемасына көңүл буралы.

Версиялоо схемасы

Бул макалада биз колдонобуз Жол учуу версияны башкаруу куралы катары (болжол менен Котормосу: биз маалымат базасын көчүрүү жөнүндө сөз болуп жатат). Албетте, биз Flyway'дин орнотулган колдоосуна ээ Spring Boot тиркемесин жазабыз жана колдонмонун контекстин орнотууда схемаларды көчүрүүнү аткарабыз. Flyway колдонуп жатканда, сиз миграциялык скрипттерди долбоорлоруңуздун папкасында сактай аласыз (демейки боюнча classpath:db/migration). Бул жерде сиз мындай миграциялык файлдардын мисалын көрө аласыз

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

Бул мисалда биз 4 миграция скрипттерин көрүп жатабыз, алар мурда аткарылбаса, тиркеме башталганда биринин артынан бири аткарылат. Файлдардын бирин карап көрөлү (V1__init.sql) мисал катары.

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

Баары өзүн-өзү түшүндүрөт: маалымат базасын кантип өзгөртүү керек экенин аныктоо үчүн SQL колдоно аласыз. Spring Boot жана Flyway жөнүндө көбүрөөк маалымат алуу үчүн, текшерүү Жазгы жүктөө документтери.

Spring Boot менен булакты башкаруу куралын колдонуу менен, сиз 2 чоң пайда аласыз:

  • сиз маалымат базасындагы өзгөрүүлөрдү коддун өзгөртүүсүнөн ажыратасыз
  • Берилиштер базасын көчүрүү колдонмоңуздун жайылуусу менен бирге ишке ашат, б.а. жайгаштыруу процессиңиз жөнөкөйлөтүлгөн

Берилиштер базасынын көйгөйлөрүн чечүү

Макаланын кийинки бөлүмүндө биз маалымат базасын өзгөртүүнүн эки ыкмасын карап чыгабыз.

  • артка туура келбегендик
  • артка шайкештик

Биринчиси алдын ала даярданбай туруп, нөлдүк токтоп калууга жол бербөө керектиги жөнүндө эскертүү катары каралат... Экинчиси, орнотууну токтоп турбастан кантип аткарууга жана ошол эле учурда артка шайкештикти сактоого байланыштуу чечимди сунуштайт.

Биз иштеп жаткан долбоорбуз жөнөкөй Spring Boot Flyway тиркемеси болот Person с first_name и last_name маалымат базасында (болжол менен котормо: Person стол жана first_name и last_name - бул андагы талаалар). Биз атын өзгөрткүбүз келет last_name в surname.

Божомолдор

Биз майда-чүйдөсүнө чейин, биз өтүнмөлөр жөнүндө бир нече божомолдор бар. Биз жетишүүнү каалаган негизги натыйжа бир кыйла жөнөкөй процесс болот.

Эскертүү. Бизнес PRO-TIP. Процесстериңизди жөнөкөйлөтүү сизге колдоо көрсөтүүгө көп акчаны үнөмдөөгө жардам берет (канчалык көп адам сиздин компанияңызда иштесе, ошончолук көп акча үнөмдөй аласыз)!

Базаны артка кайтаруунун кереги жок

Бул жайылтуу процессин жөнөкөйлөтөт (кээ бир маалымат базасын кайра кайтаруу дээрлик мүмкүн эмес, мисалы, жок кылууну артка кайтаруу). Биз колдонмолорду гана артка кайтарууну туура көрөбүз. Ушундай жол менен, сизде ар кандай маалымат базалары болсо да (мисалы, SQL жана NoSQL), жайылтуу түтүгү бирдей көрүнөт.

Колдонмонун бир версиясын артка жылдыруу АР ДАЙЫМ мүмкүн болушу керек (мындан ары эмес)

Керек болгондо гана артка кайтаруу керек. Учурдагы версияда оңой эле оңдолбогон мүчүлүштүк бар болсо, биз эң акыркы жумушчу версияга кайрыла алышыбыз керек. Бул акыркы жумушчу версия мурунку деп ойлойбуз. Бирден ашык чыгаруу үчүн код менен маалымат базасынын шайкештигин сактоо өтө кыйын жана кымбат болмок.

Эскертүү. Көбүрөөк окуу үчүн, бул макалада биз колдонмонун негизги версиясын өзгөртөбүз.

1-кадам: Баштапкы абал

Колдонмонун версиясы: 1.0.0
DB версия: v1

түшүндүрмө

Бул колдонмонун баштапкы абалы болот.

Маалыматтар базасы өзгөрөт

DB камтыйт 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');

Код өзгөртүүлөр

Колдонмо Жеке маалыматтарды сактайт 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
                + "]";
    }
}

Артка туура келбеген тилкенин атын өзгөртүү

Келгиле, мамычанын атын өзгөртүүнүн мисалын карап көрөлү:

Көңүл буруңуз. Төмөнкү мисал атайылап нерселерди бузуп салат. Биз муну маалымат базасынын шайкештиги көйгөйүн көрсөтүү үчүн көрсөтөбүз.

Колдонмонун версиясы: 2.0.0.BAD

DB версия: v2bad

түшүндүрмө

Учурдагы өзгөртүүлөр бир эле учурда эки инстанцияны (эски жана жаңы) иштетүүгө ЖОК. Ошентип, нөлдүк токтоп калууга жетишүү кыйын болот (эгерде божомолдор эске алынса, бул иш жүзүндө мүмкүн эмес).

A/B тести

Учурдагы кырдаал бизде колдонмонун версиясы бар 1.0.0, өндүрүштө жана маалымат базасында жайгаштырылган v1. Колдонмонун экинчи нускасын, версиясын жайылтышыбыз керек 2.0.0.BAD, жана маалымат базасын жаңыртыңыз v2bad.

кадамдар:

  1. версия колдонмосунун жаңы нускасы жайгаштырылган 2.0.0.BADмаалымат базасын жаңыртып турат v2bad
  2. маалымат базасында v2bad мамыча last_name мындан ары жок - деп өзгөртүлдү surname
  3. Маалыматтар базасын жана колдонмону жаңыртуу ийгиликтүү болду жана кээ бир инстанциялар иштеп жатат 1.0.0, башкалар - in 2.0.0.BAD. Баары маалымат базасына туташтырылган v2bad
  4. версиянын бардык учурлары 1.0.0 каталарды ыргыта баштайт, анткени алар мамычага маалыматтарды киргизүүгө аракет кылышат last_nameким мындан ары жок
  5. версиянын бардык учурлары 2.0.0.BAD көйгөйсүз иштей берет

Көрүнүп тургандай, эгерде биз маалымат базасына жана тиркемеге артка туура келбеген өзгөртүүлөрдү киргизсек, A/B тестирлөө мүмкүн эмес.

Колдонмону артка кайтаруу

Келгиле, A/B жайгаштырууга аракет кылгандан кийин (болжол менен per.: автор бул жерде A/B тестирлөө деген болушу мүмкүн) биз тиркемени версияга кайтарышыбыз керек деп чечтик 1.0.0. Келгиле, биз маалымат базасын артка кайтаргыбыз келбейт дейли.

кадамдар:

  1. биз версиянын колдонмо инстанциясын токтотобуз 2.0.0.BAD
  2. маалымат базасы дагы эле v2bad
  3. версиядан бери 1.0.0 анын эмне экенин түшүнбөйт surname, биз каталарды көрөбүз
  4. тозок талкаланды, биз эми кайра бара албайбыз

Көрүнүп тургандай, эгерде биз маалымат базасына жана тиркемеге артка туура келбеген өзгөртүүлөрдү киргизсек, биз мурунку версияга кайта албайбыз.

Скрипт аткаруу журналдары

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

Маалыматтар базасы өзгөрөт

Атын өзгөрткөн көчүрүү скрипти last_name в surname

Булак 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');

Атын өзгөрткөн скрипт last_name.

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

Код өзгөртүүлөр

Биз талаанын атын өзгөрттүк lastName боюнча surname.

Колоннанын атын артка карай шайкеш келтирүү

Бул эң көп кездешүүчү жагдай. Артка шайкеш келбеген өзгөртүүлөрдү киргизишибиз керек. Биз буга чейин эле нөлдүк иштебей жайгаштыруу үчүн кошумча кадамдарсыз маалымат базасын которууну жөн эле колдонбошубуз керектигин далилдегенбиз. Макаланын бул бөлүмүндө биз артка шайкештикти сактап, каалаган натыйжага жетүү үчүн маалымат базасын көчүрүү менен бирге тиркеменин 3 жайылышын аткарабыз.

Эскертүү. Эске салсак, бизде версия базасы бар v1. Ал мамычаларды камтыйт first_name и last_name. Биз өзгөрүшүбүз керек last_name боюнча surname. Бизде колдонмонун версиясы да бар 1.0.0, али колдонула элек surname.

2-кадам: фамилиясын кошуу

Колдонмонун версиясы: 2.0.0
DB версия: v2

түшүндүрмө

Жаңы тилке кошуу жана анын мазмунун көчүрүү менен биз артка шайкеш келген маалымат базасын өзгөртүүнү түзөбүз. Ошол эле учурда, эгерде биз JARды артка кайтарсак же эски JAR иштеп жатса, ал аткаруу учурунда бузулбайт.

Биз жаңы версиясын чыгарып жатабыз

кадамдар:

  1. жаңы тилке түзүү үчүн маалымат базасын көчүрүү surname. Эми сиздин DB версияңыз v2
  2. маалыматтарды көчүрүү last_name в surname. көңүл буруңуздарЭгер сизде бул маалыматтар көп болсо, анда пакеттик миграцияны карап чыгышыңыз керек!
  3. алар колдонулган кодду жаз ЭКИ и новыйжана карыган тилке. Эми колдонмоңуздун версиясы 2.0.0
  4. мамычанын маанисин оку surname, эгерде андай болбосо null, же лast_name, Эгер surname көрсөтүлгөн эмес. Сиз жок кыла аласыз getLastName() коддон, анткени ал чыгат null колдонмоңузду артка кайтарып жатканда 3.0.0 үчүн 2.0.0.

Эгер сиз Spring Boot Flyway колдонуп жатсаңыз, бул эки кадам версияны ишке киргизүү учурунда аткарылат 2.0.0 колдонмолор. Эгер сиз маалымат базасын версиялоо куралын кол менен иштетсеңиз, бул үчүн эки башка нерсени жасашыңыз керек болот (адегенде db версиясын кол менен жаңыртып, анан жаңы тиркемени жайгаштырыңыз).

Маанилүү. Жаңы түзүлгөн тилке экенин унутпаңыз КЕРЕК болуу ЖОК. Эгер сиз артка кайтарсаңыз, эски колдонмо жаңы тилке жөнүндө билбейт жана аны орнотуу учурунда орнотпойт Insert. Бирок бул чектөөнү кошсоңуз, сиздин db болот v2, бул жаңы тилкенин маанисин коюуну талап кылат. Бул чектөөлөрдү бузууга алып келет.

Маанилүү. Сиз ыкманы алып салуу керек getLastName(), анткени версияда 3.0.0 Кодексте тилке деген түшүнүк жок last_name. Бул ал жерде null орнотулат дегенди билдирет. Сиз ыкманы таштап, чектерди кошо аласыз null, бирок логикада экенине ынануу бир топ жакшы чечим болмок getSurname() сиз туура нөл эмес маанини тандадыңыз.

A/B тести

Учурдагы кырдаал бизде колдонмонун версиясы бар 1.0.0, өндүрүштө жайгаштырылган жана маалымат базасы v1. Колдонмонун версиясынын экинчи нускасын жайылтышыбыз керек 2.0.0маалымат базасын жаңыртып турат v2.

кадамдар:

  1. версия колдонмосунун жаңы нускасы жайгаштырылган 2.0.0маалымат базасын жаңыртып турат v2
  2. ошол эле учурда кээ бир суроо-талаптар версия инстанциялары тарабынан иштелип чыкты 1.0.0
  3. жаңыртуу ийгиликтүү болду жана сизде версиянын бир нече иштеп жаткан нускалары бар 1.0.0 жана башка версиялар 2.0.0. Ар бир адам маалымат базасы менен байланышат v2
  4. версия 1.0.0 маалымат базасында фамилия тилкесин эмес, версиясын колдонот 2.0.0 колдонот. Алар бири-бирине кийлигишпейт жана каталар болбошу керек.
  5. версия 2.0.0 артка шайкештикти камсыз кылуу, эски жана жаңы тилкеде маалыматтарды сактайт

Маанилүү. Эгер сизде эски/жаңы тилкедеги маанилердин негизинде нерселерди санаган суроолоруңуз болсо, сизде азыр кайталанма маанилер бар экенин эстен чыгарбоо керек (кыязы, алар дагы эле көчүп жатышат). Мисалы, фамилиясы (тилке кандай аталбасын) тамга менен башталган колдонуучулардын санын санагыңыз келсе A, андан кийин маалыматтарды көчүрүү аяктаганга чейин (oldnew мамыча) жаңы тилкени сурасаңыз, сизде дал келбеген маалыматтар болушу мүмкүн.

Колдонмону артка кайтаруу

Азыр бизде колдонмонун версиясы бар 2.0.0 жана маалымат базасында v2.

кадамдар:

  1. колдонмоңузду версияга кайтарыңыз 1.0.0.
  2. версия 1.0.0 маалымат базасында тилкени колдонбойт surname, ошондуктан артка кайтаруу ийгиликтүү болушу керек

DB өзгөрүүлөр

Маалыматтар базасында аталган тилке бар last_name.

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

Скрипт кошуу surname.

Көңүл буруңуз. Сиз кошуп жаткан тилкеге ​​эч кандай NO NULL чектөөлөрдү КОШУП АЛБАЙТ экениңизди унутпаңыз. Эгер сиз JARды артка кайтарсаңыз, эски версияда кошулган тилке жөнүндө эч кандай түшүнүк болбойт жана аны автоматтык түрдө NULL кылып коёт. Мындай чектөө бар болсо, эски колдонмо жөн эле бузулат.

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

Код өзгөртүүлөр

Биз маалыматтарды сактайбыз last_nameжана surname. Ошол эле учурда бизден окуйбуз 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;
    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-кадам: коддон фамилияны алып салуу

Колдонмонун версиясы: 3.0.0

DB версия:v3

түшүндүрмө

Эскертүү пер.: Сыягы, оригиналдуу макалада автор бул блоктун текстин 2-кадамдан жаңылып көчүрүп алган окшойт. Бул кадамда колонканы колдонгон функцияны алып салууга багытталган тиркеме кодуна өзгөртүүлөр киргизилиши керек. last_name.

Жаңы тилке кошуу жана анын мазмунун көчүрүү менен биз артка шайкеш келген маалыматтар базасынын өзгөртүүлөрүн түздүк. Ошондой эле, эгерде биз JARды артка кайтарсак же эски JAR иштеп жатса, ал аткаруу учурунда бузулбайт.

Колдонмону артка кайтаруу

Учурда бизде колдонмонун версиясы бар 3.0.0 жана маалымат базасы v3. Версия 3.0.0 маалыматтарды сактабайт last_name. Бул дегенди билдирет в surname эң актуалдуу маалымат сакталат.

кадамдар:

  1. колдонмоңузду версияга кайтарыңыз 2.0.0.
  2. версия 2.0.0 колдонот жана last_name и surname.
  3. версия 2.0.0 алат surname, эгерде нөл болбосо, антпесе -last_name

Маалыматтар базасы өзгөрөт

Маалыматтар базасында структуралык өзгөрүүлөр жок. Төмөнкү скрипт эски маалыматтарды акыркы көчүрүү үчүн аткарылат:

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

Код өзгөртүүлөр

Эскертүү пер.: Бул блоктун сүрөттөлүшү да автор тарабынан 2-кадамдан жаңылып көчүрүлгөн. Макаланын логикасына ылайык, бул кадамдагы кодго өзгөртүүлөр андан мамыча менен иштеген элементтерди алып салууга багытталышы керек. last_name.

Биз маалыматтарды сактайбыз last_nameжана surname. Мындан тышкары, биз тилкеден окуйбуз 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 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
                + "]";
    }
}

4-кадам: Фамилияны маалымат базасынан алып салуу

Колдонмонун версиясы: 4.0.0

DB версия: v4

түшүндүрмө

версия коду болгондугуна байланыштуу 3.0.0 мамычаны колдонгон эмес last_name, биз кайра жылдырып, эгерде аткаруу учурунда эч кандай жаман нерсе болбойт 3.0.0 маалымат базасынан тилкени алып салгандан кийин.

Скрипт аткаруу журналдары

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

DB өзгөрүүлөр

Салыштырмалуу v3 биз тилкени алып салабыз last_name жана жетишпеген чектөөлөрдү кошуу.

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

Код өзгөртүүлөр

Кодго эч кандай өзгөртүүлөр жок.

жыйынтыктоо

Артка шайкеш келбеген тилкенин атын өзгөртүүнү ийгиликтүү колдондук. Төмөндө аткарылган иш-аракеттердин корутундусу келтирилген:

  1. колдонмо версиясын жайылтуу 1.0.0 с v1 маалымат базасынын схемасы (мамыча аты = last_name)
  2. колдонмо версиясын жайылтуу 2.0.0, маалыматтарды сактаган last_name и surname. Колдонмо төмөнкүдөн окулат last_name. Маалымат базасы версияда v2сыяктуу мамычаларды камтыйт last_nameжана surname. surname л көчүрмөсү болуп саналатast_name. (ЭСКЕРТҮҮ: Бул тилкеде нөл эмес чектөө болбошу керек)
  3. колдонмо версиясын жайылтуу 3.0.0, анда маалыматтарды гана сактайт surname жана фамилиясынан окуйт. Маалыматтар базасына келсек, акыркы миграция жүрүп жатат last_name в surname. Ошондой эле чектөө ЖОК тартып алынып салынды last_name. Маалымат базасы азыр версияда v3
  4. колдонмо версиясын жайылтуу 4.0.0 - кодекске эч кандай өзгөртүүлөр киргизилбейт. Маалыматтар базасын жайылтуу v4, алып салат last_name. Бул жерде сиз маалымат базасына жетишпеген чектөөлөрдү кошо аласыз.

Бул ыкманы колдонуу менен сиз ар дайым маалымат базасынын/колдонмонун шайкештигин бузбастан бир версияны артка кайтара аласыз.

коду

Бул макалада колдонулган бардык коддор жеткиликтүү 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

Жазгы жүктөө үлгүсү Flyway

Бардык мисалдар алынган Spring Boot Sample Flyway.

Сиз карап көрө аласыз http://localhost:8080/flyway, скрипттердин тизмеси бар.

Бул мисал ошондой эле H2 консолун камтыйт (ат http://localhost:8080/h2-console) ошондуктан сиз маалымат базасынын абалын көрө аласыз (демейки jdbc URL болуп саналат jdbc:h2:mem:testdb).

кошумча

Биздин блогдогу башка макалаларды да окуңуз:

Source: www.habr.com

Комментарий кошуу