Defnydd Sero Amser Segur a Chronfeydd Data

Defnydd Sero Amser Segur a Chronfeydd Data

Mae'r erthygl hon yn esbonio'n fanwl sut i ddatrys problemau cydnawsedd cronfa ddata wrth eu defnyddio. Byddwn yn dweud wrthych beth all ddigwydd i'ch cymwysiadau cynhyrchu os byddwch yn ceisio defnyddio heb baratoi ymlaen llaw. Yna byddwn yn mynd trwy'r camau cylch bywyd cais sy'n ofynnol i gael dim amser segur (tua. lôn: further - sero downtime). Canlyniad ein gweithrediadau fydd cymhwyso'r newid cronfa ddata sy'n anghydnaws yn ôl mewn modd sy'n gydnaws yn ôl.

Os ydych chi eisiau deall yr enghreifftiau cod o'r erthygl, gallwch ddod o hyd iddynt yn GitHub.

Cyflwyniad

Dim defnydd o amser segur

Am gyfriniol sero defnydd amser segur? Gallwch ddweud mai dyma pan fydd eich cais yn cael ei ddefnyddio yn y fath fodd fel y gallwch gyflwyno fersiwn newydd o'r rhaglen i'r cynhyrchiad yn llwyddiannus, tra nad yw'r defnyddiwr yn sylwi nad yw ar gael. O safbwynt y defnyddiwr a'r cwmni, dyma'r senario defnydd gorau posibl oherwydd mae'n caniatáu cyflwyno nodweddion newydd a thrwsio bygiau heb amhariad.

Sut i gyflawni hyn? Mae yna sawl ffordd, dyma un ohonyn nhw:

  • defnyddio fersiwn Rhif 1 o'ch gwasanaeth
  • perfformio mudo cronfa ddata
  • Defnyddio fersiwn #2 o'ch gwasanaeth ochr yn ochr â fersiwn #1
  • cyn gynted ag y gwelwch fod fersiwn Rhif 2 yn gweithio fel y dylai, tynnwch fersiwn 1
  • yn barod!

Hawdd, ynte? Yn anffodus, nid yw mor syml â hynny, a byddwn yn edrych ar hynny'n fanwl yn nes ymlaen. Nawr, gadewch i ni wirio proses leoli weddol gyffredin arall - defnyddio gwyrddlas.

A ydych erioed wedi clywed am defnydd gwyrddlas? Mae Cloud Foundry yn gwneud hyn yn hynod o hawdd. Dim ond edrych ar yr erthygl hon, lle rydym yn disgrifio hyn yn fanylach. I grynhoi'n fyr, gadewch inni eich atgoffa sut i wneud defnydd gwyrddlas:

  • sicrhau bod dau gopi o'ch cod cynhyrchu (“glas” a “gwyrdd”) yn gweithio;
  • cyfeirio pob traffig i'r amgylchedd glas, h.y. fel bod URLs cynhyrchu yn pwyntio yno;
  • defnyddio a phrofi pob newid cymhwysiad mewn amgylchedd gwyrdd;
  • newid urls o amgylchedd glas i wyrdd

Mae defnyddio gwyrdd glas yn ddull sy'n eich galluogi i gyflwyno nodweddion newydd yn hawdd heb boeni am dorri cynhyrchiant. Mae hyn oherwydd y ffaith, hyd yn oed os bydd rhywbeth yn digwydd, y gallwch chi rolio'n ôl i'r amgylchedd blaenorol yn hawdd trwy “fflicio switsh.”

Ar ôl darllen pob un o'r uchod, efallai y byddwch yn gofyn y cwestiwn: Beth sydd gan sero amser segur i'w wneud â defnyddio Blue green?

Wel, mae ganddyn nhw gryn dipyn yn gyffredin, gan fod cynnal dau gopi o'r un amgylchedd yn gofyn am ddwywaith yr ymdrech i'w cynnal. Dyna pam mae rhai timau yn hawlio Martin Fowler, dilynwch amrywiad o'r dull hwn:

Opsiwn arall yw defnyddio'r un gronfa ddata, gan greu switshis gwyrddlas ar gyfer y we a haenau parth. Yn y dull hwn, gall y gronfa ddata fod yn broblem yn aml, yn enwedig pan fydd angen i chi newid ei sgema i gefnogi fersiwn newydd o'r feddalwedd.

A dyma ni'n dod at y brif broblem yn yr erthygl hon. Cronfa Ddata. Gadewch i ni edrych eto ar yr ymadrodd hwn.

perfformio mudo cronfa ddata.

Nawr mae'n rhaid i chi ofyn y cwestiwn i chi'ch hun - beth os nad yw'r newid cronfa ddata yn gydnaws yn ôl? Oni fydd fy fersiwn gyntaf o'r ap yn torri? Yn wir, dyma'n union beth fydd yn digwydd...

Felly, hyd yn oed er gwaethaf manteision enfawr sero amser segur / defnyddio gwyrdd glas, mae cwmnïau'n tueddu i ddilyn y broses fwy diogel ganlynol ar gyfer defnyddio eu ceisiadau:

  • paratoi pecyn gyda fersiwn newydd o'r cais
  • cau i lawr cais rhedeg
  • rhedeg sgriptiau i fudo'r gronfa ddata
  • defnyddio a lansio fersiwn newydd o'r cais

Yn yr erthygl hon, byddwn yn manylu ar sut y gallwch weithio gyda'ch cronfa ddata a'ch cod i fanteisio ar ddefnyddio dim amser segur.

Problemau cronfa ddata

Os oes gennych raglen ddi-wladwriaeth nad yw'n storio unrhyw ddata yn y gronfa ddata, gallwch gael dim amser segur ar unwaith. Yn anffodus, mae angen i'r rhan fwyaf o feddalwedd storio data yn rhywle. Dyna pam y dylech feddwl ddwywaith cyn gwneud unrhyw newidiadau i'r gylched. Cyn i ni fynd i mewn i'r manylion ar sut i newid y sgema fel nad yw'n bosibl defnyddio amser segur, gadewch i ni ganolbwyntio'n gyntaf ar y sgema fersiynu.

Cynllun fersiynu

Yn yr erthygl hon byddwn yn defnyddio Hedfan fel offeryn rheoli fersiwn (tua. Cyfieithu: rydym yn sôn am fudiadau cronfa ddata). Yn naturiol, byddwn hefyd yn ysgrifennu cymhwysiad Spring Boot sydd â chefnogaeth Flyway wedi'i ymgorffori a bydd yn perfformio mudo sgema wrth sefydlu cyd-destun y cais. Wrth ddefnyddio Flyway, gallwch storio sgriptiau mudo yn eich ffolder prosiectau (yn ddiofyn yn classpath:db/migration). Yma gallwch weld enghraifft o ffeiliau mudo o'r fath

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

Yn yr enghraifft hon gwelwn 4 sgript mudo a fydd, os na chânt eu gweithredu o'r blaen, yn cael eu gweithredu un ar ôl y llall pan fydd y cais yn dechrau. Edrychwn ar un o'r ffeiliau (V1__init.sql) fel enghraifft.

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

Mae popeth yn berffaith hunanesboniadol: gallwch ddefnyddio SQL i ddiffinio sut y dylid addasu eich cronfa ddata. I gael rhagor o wybodaeth am Spring Boot a Flyway, edrychwch allan Dogfennau Cychwyn y Gwanwyn.

Trwy ddefnyddio teclyn rheoli ffynhonnell gyda Spring Boot, cewch 2 fudd mawr:

  • rydych yn gwahanu newidiadau cronfa ddata oddi wrth newidiadau cod
  • Mae mudo cronfa ddata yn digwydd ynghyd â chyflwyno eich cais, h.y. bod eich proses lleoli yn cael ei symleiddio

Datrys problemau cronfa ddata

Yn adran nesaf yr erthygl, byddwn yn canolbwyntio ar edrych ar ddau ddull o newid cronfeydd data.

  • anghydnawsedd yn ôl
  • cydnawsedd yn ôl

Bydd yr un cyntaf yn cael ei ystyried fel rhybudd na ddylech berfformio sero amser segur heb baratoi ymlaen llaw... Mae'r ail yn cynnig ateb ar sut y gallwch chi berfformio lleoliad heb amser segur ac ar yr un pryd cynnal cydnawsedd yn ôl.

Ein prosiect y byddwn yn gweithio arno fydd cymhwysiad Spring Boot Flyway syml sydd wedi Person с first_name и last_name yn y gronfa ddata (tua. cyfieithiad: Person yn fwrdd a first_name и last_name - dyma'r meysydd sydd ynddo). Rydyn ni eisiau ailenwi last_name в surname.

Rhagdybiaethau

Cyn i ni fynd i mewn i'r manylion, mae un neu ddau o ragdybiaethau y mae angen i ni eu gwneud am ein ceisiadau. Y prif ganlyniad yr ydym am ei gyflawni fydd proses weddol syml.

Y nodyn. Busnes PRO-TIP. Gall symleiddio prosesau arbed llawer o arian i chi ar gymorth (po fwyaf o bobl sydd gennych yn gweithio i'ch cwmni, y mwyaf o arian y gallwch ei arbed)!

Nid oes angen dychwelyd y gronfa ddata

Mae hyn yn symleiddio'r broses ddefnyddio (mae bron yn amhosibl dychwelyd rhai cronfeydd data, megis dychwelyd dileu). Mae'n well gennym ddychwelyd ceisiadau yn unig. Fel hyn, hyd yn oed os oes gennych gronfeydd data gwahanol (er enghraifft, SQL a NoSQL), bydd eich piblinell lleoli yn edrych yr un peth.

Rhaid ei bod yn bosibl BOB AMSER i rolio'r cais yn ôl un fersiwn yn ôl (dim mwy)

Dim ond pan fo angen y dylid dychwelyd yn ôl. Os oes nam yn y fersiwn gyfredol nad yw'n hawdd ei drwsio, dylem allu dychwelyd i'r fersiwn weithio ddiweddaraf. Tybiwn mai'r fersiwn waith ddiweddaraf hon yw'r un blaenorol. Byddai cynnal cydweddoldeb cod a chronfa ddata ar gyfer mwy nag un cyflwyniad yn hynod o anodd a drud.

Y nodyn. Er mwyn bod yn fwy darllenadwy, yn yr erthygl hon byddwn yn newid prif fersiwn y cais.

Cam 1: Cyflwr Cychwynnol

Fersiwn ap: 1.0.0
Fersiwn DB: v1

Sylw

Dyma fydd cyflwr cychwynnol y cais.

Newidiadau cronfa ddata

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

Newidiadau cod

Mae'r rhaglen yn storio data Person i mewn 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
                + "]";
    }
}

Ail-enwi colofn yn ôl yn anghydnaws

Edrychwn ar enghraifft o sut i newid enw colofn:

Sylw. Bydd yr enghraifft ganlynol yn torri pethau'n fwriadol. Rydym yn dangos hyn i ddangos problem cydweddoldeb cronfa ddata.

Fersiwn ap: 2.0.0.BAD

Fersiwn DB: v2bad

Sylw

NID yw'r newidiadau presennol yn caniatáu i ni redeg dau enghraifft (hen a newydd) ar yr un pryd. Felly, bydd yn anodd cyflawni dim amser segur (os caiff rhagdybiaethau eu hystyried, mae'n amhosibl mewn gwirionedd).

Profi A/B

Y sefyllfa bresennol yw bod gennym fersiwn cais 1.0.0, defnyddio mewn cynhyrchu, a chronfa ddata v1. Mae angen i ni ddefnyddio ail enghraifft o'r cais, fersiwn 2.0.0.BAD, a diweddaru'r gronfa ddata i v2bad.

Camau:

  1. mae enghraifft newydd o'r cymhwysiad fersiwn yn cael ei ddefnyddio 2.0.0.BADsy'n diweddaru'r gronfa ddata i v2bad
  2. yn y gronfa ddata v2bad colofn last_name ddim yn bodoli mwyach - cafodd ei newid i surname
  3. Bu'r diweddariad cronfa ddata a'r cais yn llwyddiannus ac mae rhai achosion yn rhedeg 1.0.0, eraill - yn 2.0.0.BAD. Mae popeth wedi'i gysylltu â'r gronfa ddata v2bad
  4. pob achos o'r fersiwn 1.0.0 yn dechrau taflu gwallau oherwydd byddant yn ceisio mewnosod data yn y golofn last_namesydd ddim yn bodoli mwyach
  5. pob achos o'r fersiwn 2.0.0.BAD bydd yn gweithio heb broblemau

Fel y gallwch weld, os byddwn yn gwneud newidiadau anghydnaws yn ôl i'r gronfa ddata a'r cymhwysiad, mae profi A/B yn amhosibl.

Dychweliad cais

Gadewch i ni dybio, ar ôl ceisio gwneud defnydd A/B (tua. per .: mae'n debyg bod yr awdur yn golygu profi A/B yma) penderfynom fod angen i ni rolio'r cais yn ôl i'r fersiwn 1.0.0. Gadewch i ni ddweud nad ydym am ddychwelyd y gronfa ddata.

Camau:

  1. rydym yn atal yr enghraifft cais fersiwn 2.0.0.BAD
  2. mae'r gronfa ddata yn dal i fod v2bad
  3. ers y fersiwn 1.0.0 ddim yn deall beth ydyw surname, byddwn yn gweld gwallau
  4. mae uffern wedi torri'n rhydd, ni allwn fynd yn ôl mwyach

Fel y gallwch weld, os byddwn yn gwneud newidiadau anghydnaws yn ôl i'r gronfa ddata a'r rhaglen, ni allwn rolio'n ôl i'r fersiwn flaenorol.

Logiau gweithredu sgript

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

Newidiadau cronfa ddata

Sgript mudo sy'n ailenwi last_name в surname

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

Sgript sy'n ailenwi last_name.

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

Newidiadau cod

Rydym wedi newid enw'r cae lastName ar surname.

Ailenwi colofn mewn ffordd sy'n gydnaws yn ôl

Dyma'r sefyllfa fwyaf cyffredin y gallwn ddod ar ei thraws. Mae angen inni wneud newidiadau anghydnaws tuag yn ôl. Rydym eisoes wedi profi, ar gyfer defnyddio dim-amser segur, na ddylem gymhwyso mudo cronfa ddata heb gamau ychwanegol yn unig. Yn yr adran hon o'r erthygl, byddwn yn perfformio 3 defnydd o'r cais ynghyd â mudo cronfa ddata i gyflawni'r canlyniad a ddymunir tra'n cynnal cydnawsedd yn ôl.

Y nodyn. Dwyn i gof bod gennym gronfa ddata fersiynau v1. Mae'n cynnwys colofnau first_name и last_name. Mae'n rhaid i ni newid last_name ar surname. Mae gennym hefyd fersiwn app 1.0.0, sydd heb ei ddefnyddio eto surname.

Cam 2: Ychwanegu cyfenw

Fersiwn ap: 2.0.0
Fersiwn DB: v2

Sylw

Trwy ychwanegu colofn newydd a chopïo ei chynnwys, rydym yn creu newidiadau cronfa ddata sy'n gydnaws yn ôl. Ar yr un pryd, os byddwn yn dychwelyd y JAR neu os oes gennym hen JAR yn rhedeg, ni fydd yn torri yn ystod y gweithredu.

Rydym yn cyflwyno fersiwn newydd

Camau:

  1. perfformio mudo cronfa ddata i greu colofn newydd surname. Nawr eich fersiwn DB v2
  2. copïo data o last_name в surname. Talu sylwos oes gennych lawer o'r data hwn, dylech ystyried mudo swp!
  3. ysgrifennwch y cod lle cânt eu defnyddio Y DDAU и newyddAc yr hen colofn. Nawr eich fersiwn app 2.0.0
  4. darllenwch y gwerth o'r golofn surname, os nad ydyw null, neu o last_nameos surname heb ei nodi. Gallwch ddileu getLastName() o'r cod, gan y bydd yn allbwn null wrth rolio'ch cais yn ôl o 3.0.0 i 2.0.0.

Os ydych chi'n defnyddio Spring Boot Flyway, bydd y ddau gam hyn yn cael eu perfformio yn ystod cychwyn y fersiwn 2.0.0 ceisiadau. Os ydych chi'n rhedeg yr offeryn fersiwn cronfa ddata â llaw, bydd yn rhaid i chi wneud dau beth gwahanol i wneud hyn (diweddarwch y fersiwn db â llaw yn gyntaf ac yna defnyddio'r rhaglen newydd).

Mae'n bwysig. Cofiwch fod y golofn newydd ei chreu NI DDYLAI i fod NID YN NULL. Os byddwch chi'n dychwelyd, nid yw'r hen raglen yn gwybod am y golofn newydd ac ni fydd yn ei gosod yn ystod Insert. Ond os ychwanegwch y cyfyngiad hwn a bydd eich db v2, bydd hyn yn gofyn am osod gwerth y golofn newydd. A fydd yn arwain at dorri cyfyngiadau.

Mae'n bwysig. Dylech gael gwared ar y dull getLastName(), oherwydd yn y fersiwn 3.0.0 Nid oes unrhyw gysyniad o golofn yn y cod last_name. Mae hyn yn golygu y bydd null yn cael ei osod yno. Gallwch adael y dull ac ychwanegu sieciau ar gyfer null, ond ateb llawer gwell fyddai gwneud yn siŵr hynny yn y rhesymeg getSurname() dewisoch y gwerth di-sero cywir.

Profi A/B

Y sefyllfa bresennol yw bod gennym fersiwn cais 1.0.0, a ddefnyddir wrth gynhyrchu, a'r gronfa ddata yn v1. Mae angen i ni ddefnyddio ail enghraifft o'r cais fersiwn 2.0.0a fydd yn diweddaru'r gronfa ddata i v2.

Camau:

  1. mae enghraifft newydd o'r cymhwysiad fersiwn yn cael ei ddefnyddio 2.0.0sy'n diweddaru'r gronfa ddata i v2
  2. yn y cyfamser roedd rhai ceisiadau'n cael eu prosesu gan enghreifftiau o fersiynau 1.0.0
  3. roedd y diweddariad yn llwyddiannus ac mae gennych chi sawl achos rhedeg o'r cais fersiwn 1.0.0 a fersiynau eraill 2.0.0. Mae pawb yn cyfathrebu â'r gronfa ddata yn v2
  4. fersiwn 1.0.0 nid yw'n defnyddio'r golofn cyfenw yn y gronfa ddata, ond y fersiwn 2.0.0 defnyddiau. Nid ydynt yn ymyrryd â'i gilydd, ac ni ddylai fod unrhyw wallau.
  5. fersiwn 2.0.0 yn storio data yn y golofn hen a newydd, gan sicrhau cydnawsedd yn ôl

Mae'n bwysig. Os oes gennych unrhyw ymholiadau sy'n cyfrif eitemau yn seiliedig ar werthoedd o'r golofn hen/newydd, dylech gofio bod gennych werthoedd dyblyg bellach (yn fwyaf tebygol eu bod yn dal i fudo). Er enghraifft, os ydych am gyfrif nifer y defnyddwyr y dechreuodd eu henw olaf (beth bynnag yw'r golofn) gyda'r llythyren A, yna nes bod mudo data wedi'i gwblhau (oldnew colofn) efallai y bydd gennych ddata anghyson os ydych yn ymholi am golofn newydd.

Dychweliad cais

Nawr mae gennym fersiwn app 2.0.0 a chronfa ddata yn v2.

Camau:

  1. rholio eich cais yn ôl i fersiwn 1.0.0.
  2. fersiwn 1.0.0 ddim yn defnyddio colofn yn y gronfa ddata surname, felly dylai'r dychwelyd fod yn llwyddiannus

Newidiadau DB

Mae'r gronfa ddata yn cynnwys colofn o'r enw last_name.

Sgript ffynhonnell hedfan:

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

Ychwanegu sgript surname.

Sylw. Cofiwch NA ALLWCH YCHWANEGU unrhyw gyfyngiadau NID NULL i'r golofn rydych yn ei hychwanegu. Os dychwelwch y JAR, ni fydd gan yr hen fersiwn unrhyw syniad am y golofn ychwanegol a bydd yn ei gosod yn NULL yn awtomatig. Os oes cyfyngiad o'r fath, bydd yr hen gais yn torri.

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

Newidiadau cod

Rydym yn storio data fel last_name, ac yn surname. Ar yr un pryd darllenwn o last_name, gan mai'r golofn hon yw'r mwyaf perthnasol. Yn ystod y broses leoli, mae'n bosibl bod rhai ceisiadau wedi'u prosesu gan achos cais nad yw wedi'i ddiweddaru eto.

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

Cam 3: Tynnu last_name o'r cod

Fersiwn ap: 3.0.0

Fersiwn DB:v3

Sylw

Nodyn per .: Mae'n debyg, yn yr erthygl wreiddiol, gwnaeth yr awdur gopïo testun y bloc hwn ar gam o gam 2. Ar y cam hwn, dylid gwneud newidiadau yng nghod y cais gyda'r nod o ddileu'r swyddogaeth sy'n defnyddio'r golofn last_name.

Trwy ychwanegu colofn newydd a chopïo ei chynnwys, fe wnaethom greu newidiadau cronfa ddata gydnaws yn ôl. Hefyd, os ydym yn dychwelyd y JAR neu os oes gennym hen JAR yn rhedeg, ni fydd yn torri yn ystod y gweithredu.

Dychweliad cais

Ar hyn o bryd mae gennym fersiwn app 3.0.0 a chronfa ddata v3. Fersiwn 3.0.0 nid yw'n arbed data i last_name. Mae hyn yn golygu bod yn surname mae'r wybodaeth ddiweddaraf yn cael ei storio.

Camau:

  1. rholio eich cais yn ôl i fersiwn 2.0.0.
  2. fersiwn 2.0.0 defnyddiau a last_name и surname.
  3. fersiwn 2.0.0 bydd yn cymryd surname, os nad yw'n sero, fel arall -last_name

Newidiadau cronfa ddata

Nid oes unrhyw newidiadau strwythurol yn y gronfa ddata. Gweithredir y sgript ganlynol i berfformio mudo terfynol yr hen ddata:

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

Newidiadau cod

Nodyn per .: Cafodd y disgrifiad o'r bloc hwn hefyd ei gopïo ar gam gan yr awdur o gam 2. Yn unol â rhesymeg yr erthygl, dylai newidiadau yn y cod yn y cam hwn gael eu hanelu at dynnu oddi arno elfennau sy'n gweithio gyda'r golofn last_name.

Rydym yn storio data fel last_name, ac yn surname. Yn ogystal, rydym yn darllen o'r golofn last_name, gan mai dyma'r mwyaf perthnasol. Yn ystod y broses leoli, gall rhai ceisiadau gael eu prosesu gan enghraifft nad yw wedi'i huwchraddio eto.

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

Cam 4: Tynnu last_name o'r gronfa ddata

Fersiwn ap: 4.0.0

Fersiwn DB: v4

Sylw

Oherwydd y ffaith bod y cod fersiwn 3.0.0 heb ddefnyddio'r golofn last_name, ni fydd dim byd drwg yn digwydd yn ystod y dienyddiad os byddwn yn dychwelyd i 3.0.0 ar ôl tynnu colofn o'r gronfa ddata.

Logiau gweithredu sgript

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

Newidiadau DB

Cymharol v3 rydyn ni'n tynnu'r golofn last_name ac ychwanegu cyfyngiadau coll.

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

Newidiadau cod

Nid oes unrhyw newidiadau i'r cod.

Allbwn

Llwyddwyd i gymhwyso newid enw colofn yn ôl-anghydnaws trwy berfformio sawl gosodiad sy'n gydnaws yn ôl. Isod mae crynodeb o'r camau gweithredu a gyflawnwyd:

  1. defnyddio fersiwn y cais 1.0.0 с v1 sgema cronfa ddata (enw colofn = last_name)
  2. defnyddio fersiwn y cais 2.0.0, sy'n storio data i mewn last_name и surname. Mae'r cais yn darllen o last_name. Mae'r gronfa ddata mewn fersiwn v2yn cynnwys colofnau fel last_nameAc surname. surname yn gopi o last_name. (NODER: Ni ddylai’r golofn hon fod â chyfyngiad nid nwl)
  3. defnyddio fersiwn y cais 3.0.0, sydd ond yn storio data i mewn surname ac yn darllen o gyfenw. O ran y gronfa ddata, mae'r mudo olaf yn digwydd last_name в surname. Hefyd yn gyfyngiad NID YN NULL tynnu o last_name. Mae'r gronfa ddata bellach mewn fersiwn v3
  4. defnyddio fersiwn y cais 4.0.0 - ni wneir unrhyw newidiadau i'r cod. Defnyddio cronfa ddata v4, sy'n dileu last_name. Yma gallwch ychwanegu unrhyw gyfyngiadau coll i'r gronfa ddata.

Trwy ddilyn y dull hwn, gallwch bob amser rolio un fersiwn yn ôl heb dorri cydnawsedd cronfa ddata/cymhwysiad.

Cod

Mae'r holl god a ddefnyddir yn yr erthygl hon ar gael yn Github. Isod mae disgrifiad ychwanegol.

Prosiectau

Ar ôl clonio'r ystorfa, fe welwch y strwythur ffolder canlynol.

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

Sgriptiau

Gallwch redeg y sgriptiau a ddisgrifir yn y sgriptiau isod, a fydd yn dangos newidiadau sy'n gydnaws yn ôl ac anghydnaws i'r gronfa ddata.

I weld yr achos gyda newidiadau sy'n gydnaws yn ôl, rhedeg:

./scripts/scenario_backward_compatible.sh

Ac i weld achos gyda newidiadau anghydnaws tuag yn ôl, rhedeg:

./scripts/scenario_backward_incompatible.sh

Llwybr Hedfan Sampl Boot Gwanwyn

Cymerir pob enghraifft o Spring Boot Sample Flyway.

Gallwch chi gymryd golwg ar http://localhost:8080/flyway, mae rhestr o sgriptiau.

Mae'r enghraifft hon hefyd yn cynnwys y consol H2 (yn http://localhost:8080/h2-console) fel y gallwch weld statws y gronfa ddata (URL jdbc diofyn yw jdbc:h2:mem:testdb).

ychwanegol

Darllenwch erthyglau eraill ar ein blog hefyd:

Ffynhonnell: hab.com

Ychwanegu sylw