هرڅومره ژر چې تاسو وګورئ چې دا نسخه نمبر 2 کار کوي لکه څنګه چې باید وي، نسخه نمبر 1 لرې کړئ
چمتو!
اسانه، دا نه ده؟ له بده مرغه، دا دومره ساده نه دی، او موږ به وروسته په تفصیل سره وګورو. اوس راځئ چې د ځای پرځای کولو بل خورا عام پروسه وګورو - blue green deployment.
په دې مثال کې موږ د مهاجرت 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 and Flyway پاڼې اړوند نور معلومات په فسبوک کې اوګورئ د پسرلي بوټ اسناد.
لومړی به د اخطار په توګه وګڼل شي چې تاسو باید له لومړني چمتووالي پرته د صفر ځنډ وخت ګمارنه ترسره نه کړئ ... دوهم یو حل وړاندې کوي چې تاسو څنګه کولی شئ پرته له ځنډ څخه ګمارنه ترسره کړئ او په ورته وخت کې شاته مطابقت وساتئ.
زموږ پروژه چې موږ به یې کار کوو د پسرلي بوټ فلای وی یو ساده غوښتنلیک وي چې لري Person с first_name и last_name په ډیټابیس کې (نږدې ژباړه: Person یو میز دی او first_name и last_name - دا په دې کې ساحې دي). موږ غواړو نوم بدل کړو last_name в surname.
دا د ځای پرځای کولو پروسه ساده کوي (د ډیټابیس ځینې رول بیکونه تقریبا ناممکن دي، لکه د حذف کولو رول بیک). موږ غوره کوو چې یوازې غوښتنلیکونه بیرته راوباسئ. په دې توګه، حتی که تاسو مختلف ډیټابیسونه ولرئ (د بیلګې په توګه، 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
+ "]";
}
}
شاته د نامناسب کالم نوم بدلول
راځئ چې یو مثال وګورو چې څنګه د کالم نوم بدل کړو:
پاملرنه. لاندې مثال به په قصدي ډول شیان مات کړي. موږ دا د ډیټابیس مطابقت ستونزه ښودلو لپاره ښیې.
له نسخې راهیسې 1.0.0 نه پوهیږي چې دا څه دي surname، موږ به تېروتنې وګورو
دوزخ خلاص شو، موږ نور بیرته نه شو تللای
لکه څنګه چې تاسو لیدلی شئ، که موږ په ډیټابیس او غوښتنلیک کې شاته غیر متقابل بدلونونه رامینځته کړو، موږ نشو کولی بیرته پخوانۍ نسخه ته لاړ شو.
د سکریپټ اجرا کولو لاګونه
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
سرچینه فلای وی سکریپټ:
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 روان وي، دا به د اجرا کولو پرمهال مات نشي.
له کالم څخه ارزښت ولولئ surname, که دا نه وي null، یا له l څخهast_nameکه surname معلوم نه ده. تاسو کولی شئ حذف کړئ getLastName() د کوډ څخه، ځکه چې دا به تولید شي null کله چې خپل غوښتنلیک بیرته راوباسئ 3.0.0 پورې 2.0.0.
که تاسو د پسرلي بوټ الوتنې کاروئ، دا دوه مرحلې به د نسخې پیل کولو پرمهال ترسره شي 2.0.0 غوښتنلیکونه که تاسو د ډیټابیس نسخه کولو وسیله په لاسي ډول پرمخ وړئ ، نو تاسو به د دې کولو لپاره دوه مختلف شیان ترسره کړئ (لومړی د db نسخه په لاسي ډول تازه کړئ او بیا نوی غوښتنلیک ځای په ځای کړئ).
دا مهمه ده. په یاد ولرئ چې نوی جوړ شوی کالم باید نه وي نه. که تاسو یو رول بیک وکړئ، زوړ اپلیکیشن د نوي کالم په اړه نه پوهیږي او دا به په وخت کې نصب نه کړي. Insert. مګر که تاسو دا خنډ اضافه کړئ او ستاسو db به وي v2، دا به د نوي کالم ارزښت تنظیم کولو ته اړتیا ولري. کوم چې به د بندیزونو سرغړونې لامل شي.
دا مهمه ده. تاسو باید طریقه لرې کړئ getLastName()، ځکه چې په نسخه کې 3.0.0 په کوډ کې د کالم مفهوم شتون نلري last_name. دا پدې مانا ده چې نول به هلته تنظیم شي. تاسو کولی شئ میتود پریږدئ او چیکونه اضافه کړئ null، مګر یو ډیر ښه حل به دا وي چې ډاډ ترلاسه کړئ چې په منطق کې getSurname() تاسو صحیح غیر صفر ارزښت غوره کړی.
د A/B ازموینه
اوسنی حالت دا دی چې موږ د اپلیکیشن نسخه لرو 1.0.0په تولید او ډیټابیس کې ځای پرځای شوي v1. موږ اړتیا لرو د نسخې غوښتنلیک دوهم مثال ځای په ځای کړو 2.0.0کوم چې به ډیټابیس ته تازه کړي v2.
نسخه 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.
پاملرنه. په یاد ولرئ چې تاسو نشئ کولی په هغه کالم کې چې تاسو یې اضافه کوئ هیڅ غیر محدود محدودیتونه اضافه کړئ. که تاسو 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
تبصره
نوټ per.: په ښکاره ډول، په اصلي مقاله کې لیکوال په غلطۍ سره د دې بلاک متن له 2 مرحلې څخه کاپي کړی. پدې مرحله کې، د غوښتنلیک کوډ کې باید بدلونونه راوستل شي چې هدف یې د هغه فعالیت لیرې کول دي چې کالم کاروي. last_name.
د نوي کالم په اضافه کولو او د هغې مینځپانګې کاپي کولو سره ، موږ د شاته مطابقت لرونکي ډیټابیس بدلونونه رامینځته کړل. همچنان ، که موږ JAR بیرته راوباسئ یا یو زوړ JAR روان وي ، نو دا به د اجرا کولو پرمهال مات نشي.
د غوښتنلیک رول بیک
اوس مهال موږ د اپلیکیشن نسخه لرو 3.0.0 او ډیټابیس v3. نسخه 3.0.0 ته معلومات نه خوندي کوي last_name. دا پدې مانا ده چې په کې surname تر ټولو تازه معلومات ساتل کیږي.
ګامونه:
خپل غوښتنلیک بیرته نسخه ته واړوئ 2.0.0.
نسخه 2.0.0 کاروي او last_name и surname.
نسخه 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;
کوډ بدلونونه
نوټ پر. 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"}
-- 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;
├── 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)