
μ΄ λ¬Έμμμλ λ°°ν¬ μ λ°μ΄ν°λ² μ΄μ€ νΈνμ± λ¬Έμ λ₯Ό ν΄κ²°νλ λ°©λ²μ μμΈν μ€λͺ ν©λλ€. μ¬μ μ€λΉ μμ΄ λ°°ν¬νλ €κ³ νλ©΄ νλ‘λμ μ ν리μΌμ΄μ μ μ΄λ€ μΌμ΄ λ°μν μ μλμ§ μλ €λλ¦¬κ² μ΅λλ€. κ·Έλ° λ€μ κ°λ μ€μ§ μκ°μ΄ μμ΄μΌ νλ μ ν리μΌμ΄μ μλͺ μ£ΌκΈ° λ¨κ³λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€(λλ΅. μ°¨μ : μΆκ° - κ°λ μ€μ§ μκ° μμ). μ°λ¦¬ μμ μ κ²°κ³Όλ μ΄μ λ²μ κ³Ό νΈνλμ§ μλ λ°μ΄ν°λ² μ΄μ€ λ³κ²½ μ¬νμ μ΄μ λ²μ κ³Ό νΈνλλ λ°©μμΌλ‘ μ μ©νλ κ²μ λλ€.
κΈ°μ¬μ μ½λ μμ λ₯Ό μ΄ν΄νλ €λ©΄ λ€μμμ μ°Ύμ μ μμ΅λλ€. .
μκ°
λ€μ΄νμ μλ λ°°ν¬
μ λ§ μ λΉλ‘μ΄λ°μ? λ€μ΄νμ μλ λ°°ν¬? μ΄λ μ¬μ©μκ° μ¬μ©ν μ μμμ μΈμνμ§ λͺ»νλ λμ μ ν리μΌμ΄μ μ μ λ²μ μ νλ‘λμ μ μ±κ³΅μ μΌλ‘ λμ ν μ μλ λ°©μμΌλ‘ μ ν리μΌμ΄μ μ΄ λ°°ν¬λλ λλΌκ³ λ§ν μ μμ΅λλ€. μ¬μ©μ λ° νμ¬ κ΄μ μμ λ³Ό λ μ΄λ μ€λ¨ μμ΄ μλ‘μ΄ κΈ°λ₯μ λμ νκ³ λ²κ·Έλ₯Ό μμ ν μ μκΈ° λλ¬Έμ κ°λ₯ν μ΅μμ λ°°ν¬ μλ리μ€μ λλ€.
μ΄κ²μ λ¬μ±νλ λ°©λ²μ 무μμ λκΉ? μ¬λ¬ κ°μ§ λ°©λ²μ΄ μλλ°, κ·Έ μ€ νλλ λ€μκ³Ό κ°μ΅λλ€.
- μλΉμ€ λ²μ 1μ λ°°ν¬νμΈμ.
- λ°μ΄ν°λ² μ΄μ€ λ§μ΄κ·Έλ μ΄μ μν
- λ²μ 2κ³Ό λ³λ ¬λ‘ μλΉμ€ λ²μ 1λ₯Ό λ°°ν¬ν©λλ€.
- λ²μ 2κ° μ μμ μΌλ‘ μλνλ κ²μ νμΈνμλ§μ λ²μ 1μ μ κ±°νμμμ€.
- λλ!
μ½μ§μ? λΆννκ²λ μ΄λ κ·Έλ κ² κ°λ¨νμ§ μμ΅λλ€. μ΄μ λν΄μλ λμ€μ μμΈν μ΄ν΄λ³΄κ² μ΅λλ€. μ΄μ λ λ€λ₯Έ μΌλ°μ μΈ λ°°ν¬ νλ‘μΈμ€μΈ νλμ λ Ήμ λ°°ν¬λ₯Ό νμΈν΄ λ³΄κ² μ΅λλ€.
λ€μ΄λ³Έ μ μ΄ μλμ? ? Cloud Foundryλ₯Ό μ¬μ©νλ©΄ μ΄λ₯Ό λ§€μ° μ½κ² μνν μ μμ΅λλ€. κ·Έλ₯ λ΄ , μ¬κΈ°μ μ΄μ λν΄ λ μμΈν μ€λͺ ν©λλ€. κ°λ΅νκ² μμ½νμλ©΄, λΈλ£¨ κ·Έλ¦° λ°°ν¬λ₯Ό μννλ λ°©λ²μ μκΈ°μμΌ λλ¦¬κ² μ΅λλ€.
- νλ‘λμ μ½λ μ¬λ³Έ XNUMXκ°("νλμ" λ° "λ Ήμ")κ° μλνλμ§ νμΈν©λλ€.
- λͺ¨λ νΈλν½μ λΈλ£¨ νκ²½μΌλ‘ 보λ λλ€. μ¦, νλ‘λμ 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μ ν¨κ» μμ€ μ μ΄ λꡬλ₯Ό μ¬μ©νλ©΄ λ κ°μ§ ν° μ΄μ μ μ»μ μ μμ΅λλ€.
- λ°μ΄ν°λ² μ΄μ€ λ³κ²½ μ¬νκ³Ό μ½λ λ³κ²½ μ¬νμ λΆλ¦¬ν©λλ€.
- λ°μ΄ν°λ² μ΄μ€ λ§μ΄κ·Έλ μ΄μ μ μ ν리μΌμ΄μ μΆμμ ν¨κ» λ°μν©λλ€. λ°°ν¬ νλ‘μΈμ€κ° λ¨μνλ©λλ€.
λ°μ΄ν°λ² μ΄μ€ λ¬Έμ ν΄κ²°
κΈ°μ¬μ λ€μ μΉμ μμλ λ°μ΄ν°λ² μ΄μ€ λ³κ²½μ λν λ κ°μ§ μ κ·Ό λ°©μμ μ΄ν΄λ³΄λ λ° μ€μ μ λ κ²μ λλ€.
- μ΄μ λ²μ κ³Όμ λΉνΈνμ±
- νμ νΈνμ±
첫 λ²μ§Έλ μ¬μ μ€λΉ μμ΄ μ λ‘ λ€μ΄νμ λ°°ν¬λ₯Ό μννλ©΄ μ λλ€λ κ²½κ³ λ‘ κ°μ£Όλ©λλ€... λ λ²μ§Έλ λ€μ΄νμ μμ΄ λ°°ν¬λ₯Ό μννλ λμμ μ΄μ λ²μ κ³Όμ νΈνμ±μ μ μ§ν μ μλ λ°©λ²μ λν μ루μ μ μ 곡ν©λλ€.
μ°λ¦¬κ° μμ
ν νλ‘μ νΈλ κ°λ¨ν Spring Boot Flyway μ ν리μΌμ΄μ
μ΄ λ κ²μ
λλ€. Person Ρ first_name ΠΈ last_name λ°μ΄ν°λ² μ΄μ€(λλ΅. λ²μ: Person λ ν
μ΄λΈμ΄κ³ fμ
λλ€irst_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
+ "]";
}
}μ΄μ λ²μ κ³Ό νΈνλμ§ μλ μ΄ μ΄λ¦ λ°κΎΈκΈ°
μ΄ μ΄λ¦μ λ³κ²½νλ λ°©λ²μ μλ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
μ£Όμ. λ€μ μμ μμλ μλμ μΌλ‘ μμ μ μ€λ¨ν©λλ€. μ°λ¦¬λ λ°μ΄ν°λ² μ΄μ€ νΈνμ± λ¬Έμ λ₯Ό 보μ¬μ£ΌκΈ° μν΄ μ΄κ²μ 보μ¬μ€λλ€.
μ± λ²μ : 2.0.0.BAD
DB λ²μ : v2bad
λ Όν
νμ¬ λ³κ²½ μ¬νμΌλ‘ μΈν΄ λ κ°μ μΈμ€ν΄μ€(μ΄μ μΈμ€ν΄μ€μ μ μΈμ€ν΄μ€)λ₯Ό λμμ μ€νν μ μμ΅λλ€. λ°λΌμ κ°λ μ€μ§ μκ° μ λ‘ λ°°ν¬λ λ¬μ±νκΈ° μ΄λ ΅μ΅λλ€(κ°μ μ κ³ λ €νλ©΄ μ€μ λ‘λ λΆκ°λ₯ν©λλ€).
A/B ν μ€νΈ
νμ¬ μν©μ μ ν리μΌμ΄μ
λ²μ μ΄ μλ€λ κ²μ
λλ€. 1.0.0, νλ‘λμ
λ° λ°μ΄ν°λ² μ΄μ€μ λ°°ν¬ v1. μ ν리μΌμ΄μ
μ λ λ²μ§Έ μΈμ€ν΄μ€ λ²μ μ λ°°ν¬ν΄μΌ ν©λλ€. 2.0.0.BAD, λ°μ΄ν°λ² μ΄μ€λ₯Ό λ€μμΌλ‘ μ
λ°μ΄νΈν©λλ€. v2bad.
λ¨κ³ :
- λ²μ μ ν리μΌμ΄μ
μ μ μΈμ€ν΄μ€κ° λ°°ν¬λ©λλ€.
2.0.0.BADλ°μ΄ν°λ² μ΄μ€λ₯Ό μ λ°μ΄νΈν©λλ€.v2bad - λ°μ΄ν°λ² μ΄μ€μμ
v2badμ΄last_nameλ μ΄μ μ‘΄μ¬νμ§ μμ΅λλ€. λ€μμΌλ‘ λ³κ²½λμμ΅λλ€.surname - λ°μ΄ν°λ² μ΄μ€ λ° μ ν리μΌμ΄μ
μ
λ°μ΄νΈκ° μ±κ³΅νμΌλ©° μΌλΆ μΈμ€ν΄μ€κ° μ€ν μ€μ
λλ€.
1.0.0, κΈ°ν - μ2.0.0.BAD. λͺ¨λ κ²μ΄ λ°μ΄ν°λ² μ΄μ€μ μ°κ²°λμ΄ μμ΅λλ€v2bad - λ²μ μ λͺ¨λ μΈμ€ν΄μ€
1.0.0μ΄μ λ°μ΄ν°λ₯Ό μ½μ νλ €κ³ μλνκΈ° λλ¬Έμ μ€λ₯κ° λ°μνκΈ° μμν©λλ€.last_nameλ μ΄μ μ‘΄μ¬νμ§ μλ μ¬λ - λ²μ μ λͺ¨λ μΈμ€ν΄μ€
2.0.0.BADλ¬Έμ μμ΄ μλν κ²μ΄λ€
보μλ€μνΌ, λ°μ΄ν°λ² μ΄μ€μ μ ν리μΌμ΄μ μ μ΄μ λ²μ κ³Ό νΈνλμ§ μλ λ³κ²½ μ¬νμ μ μ©νλ©΄ A/B ν μ€νΈκ° λΆκ°λ₯ν©λλ€.
μ ν리μΌμ΄μ λ‘€λ°±
A/B λ°°ν¬λ₯Ό μλν ν (λλ΅. λΉ: μ μλ μλ§λ μ¬κΈ°μ A/B ν
μ€νΈλ₯Ό μλ―Ένμ κ²μ
λλ€.) μ°λ¦¬λ μ ν리μΌμ΄μ
μ μ΄μ λ²μ μΌλ‘ λ‘€λ°±ν΄μΌ νλ€κ³ κ²°μ νμ΅λλ€. 1.0.0. λ°μ΄ν°λ² μ΄μ€λ₯Ό λ‘€λ°±νκ³ μΆμ§ μλ€κ³ κ°μ ν΄ λ³΄κ² μ΅λλ€.
λ¨κ³ :
- λ²μ μ ν리μΌμ΄μ
μΈμ€ν΄μ€λ₯Ό μ€μ§ν©λλ€.
2.0.0.BAD - λ°μ΄ν°λ² μ΄μ€λ μμ§
v2bad - λ²μ λΆν°
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. μ΄μ DB λ²μ v2 - λ°μ΄ν° 볡μ¬
last_nameΠ²surname. μ£Όμμ΄ λ°μ΄ν°κ° λ§μΌλ©΄ μΌκ΄ λ§μ΄κ·Έλ μ΄μ μ κ³ λ €ν΄μΌ ν©λλ€! - μ¬μ©λλ κ³³μ μ½λλ₯Ό μμ±νμΈμ. λ λ€ ΠΈ μλ‘μ΄κ³Ό μ€λ λ μ΄. μ΄μ μ± λ²μ
2.0.0 - μ΄μμ κ°μ μ½μ΅λλ€.
surname, κ·Έλ μ§ μμ κ²½μ°null, μλλ©΄ λ΄κ°ast_name, ifsurnameλͺ μλμ§ μμ. μμ ν μ μμ΅λλ€getLastName()μ½λμμ μΆλ ₯λλ―λ‘nullμ ν리μΌμ΄μ μ λ‘€λ°±ν λ3.0.0μ2.0.0.
Spring Boot Flywayλ₯Ό μ¬μ©νλ κ²½μ° λ²μ μμ μ€μ μ΄ λ λ¨κ³κ° μνλ©λλ€. 2.0.0 μμ© νλ‘κ·Έλ¨. λ°μ΄ν°λ² μ΄μ€ λ²μ κ΄λ¦¬ λꡬλ₯Ό μλμΌλ‘ μ€ννλ κ²½μ° μ΄λ₯Ό μννλ €λ©΄ λ κ°μ§ λ€λ₯Έ μμ
μ μνν΄μΌ ν©λλ€(λ¨Όμ db λ²μ μ μλμΌλ‘ μ
λ°μ΄νΈν λ€μ μ μ ν리μΌμ΄μ
μ λ°°ν¬).
κ·Έκ²μ μ€μν©λλ€. μλ‘ μμ±λ μ΄μ νμ§ λ§μμΌνλ€ μλ€ NULL μλ. λ‘€λ°±μ μννλ κ²½μ° μ΄μ μ ν리μΌμ΄μ μ μ μ΄μ λν΄ μμ§ λͺ»νλ―λ‘ λ‘€λ°± μ€μ μ΄λ₯Ό μ€μΉνμ§ μμ΅λλ€.
Insert.νμ§λ§ μ΄ μ μ½ μ‘°κ±΄μ μΆκ°νλ©΄ DBλv2, μ μ΄μ κ°μ μ€μ ν΄μΌ ν©λλ€. μ΄λ μ ν μλ°μΌλ‘ μ΄μ΄μ§ κ²μ λλ€.κ·Έκ²μ μ€μν©λλ€. λ©μλλ₯Ό μ κ±°ν΄μΌ ν©λλ€.
getLastName(), λ²μ μμλ3.0.0μ½λμλ μ΄ κ°λ μ΄ μμ΅λλ€.last_name. μ΄λ nullμ΄ κ±°κΈ°μ μ€μ λλ€λ κ²μ μλ―Έν©λλ€. λ©μλλ₯Ό μ’ λ£νκ³ λ€μμ λν κ²μ¬λ₯Ό μΆκ°ν μ μμ΅λλ€.nullνμ§λ§ ν¨μ¬ λ λμ ν΄κ²°μ± μ λ Όλ¦¬μμ λ€μμ νμΈνλ κ²μ λλ€.getSurname()XNUMXμ΄ μλ μ¬λ°λ₯Έ κ°μ μ ννμ΅λλ€.
A/B ν μ€νΈ
νμ¬ μν©μ μ ν리μΌμ΄μ
λ²μ μ΄ μλ€λ κ²μ
λλ€. 1.0.0, νλ‘λμ
μ λ°°ν¬λκ³ λ°μ΄ν°λ² μ΄μ€λ v1. λ²μ μ ν리μΌμ΄μ
μ λ λ²μ§Έ μΈμ€ν΄μ€λ₯Ό λ°°ν¬ν΄μΌ ν©λλ€. 2.0.0λ°μ΄ν°λ² μ΄μ€λ₯Ό λ€μμΌλ‘ μ
λ°μ΄νΈν©λλ€. v2.
λ¨κ³ :
- λ²μ μ ν리μΌμ΄μ
μ μ μΈμ€ν΄μ€κ° λ°°ν¬λ©λλ€.
2.0.0λ°μ΄ν°λ² μ΄μ€λ₯Ό μ λ°μ΄νΈν©λλ€.v2 - κ·Έ λμ μΌλΆ μμ²μ΄ λ²μ μΈμ€ν΄μ€μ μν΄ μ²λ¦¬λμμ΅λλ€.
1.0.0 - μ
λ°μ΄νΈκ° μ±κ³΅νμΌλ©° λ²μ μ ν리μΌμ΄μ
μ μ€ν μ€μΈ μΈμ€ν΄μ€κ° μ¬λ¬ κ° μμ΅λλ€.
1.0.0κ·Έλ¦¬κ³ λ€λ₯Έ λ²μ 2.0.0.λͺ¨λ μ¬λμ λ°μ΄ν°λ² μ΄μ€μ ν΅μ ν©λλ€.v2 - λ²μ
1.0.0λ°μ΄ν°λ² μ΄μ€μ μ± μ΄μ μ¬μ©νμ§ μμ§λ§ λ²μ 2.0.0μ¬μ©ν©λλ€. μλ‘ κ°μνμ§ μμΌλ©° μ€λ₯κ° μμ΄μΌ ν©λλ€. - λ²μ
2.0.0μ΄μ μ΄κ³Ό μ μ΄ λͺ¨λμ λ°μ΄ν°λ₯Ό μ μ₯νμ¬ μ΄μ λ²μ κ³Όμ νΈνμ±μ 보μ₯ν©λλ€.
κ·Έκ²μ μ€μν©λλ€. μ΄μ /μ μ΄μ κ°μ κΈ°μ€μΌλ‘ νλͺ© μλ₯Ό κ³μ°νλ μΏΌλ¦¬κ° μλ κ²½μ° μ΄μ μ€λ³΅λ κ°μ΄ μλ€λ μ μ κΈ°μ΅ν΄μΌ ν©λλ€(μμ§ λ§μ΄κ·Έλ μ΄μ μ€μΌ κ°λ₯μ±μ΄ λμ). μλ₯Ό λ€μ΄, μ±(μ΄ μ΄λ¦μ κ΄κ³μμ΄)μ΄ λ¬Έμλ‘ μμνλ μ¬μ©μ μλ₯Ό κ³μ°νλ €λ κ²½μ°
A, λ°μ΄ν° λ§μ΄κ·Έλ μ΄μ μ΄ μλ£λ λκΉμ§(oldβnewμ΄) μ μ΄μ 쿼리νλ©΄ λ°μ΄ν°κ° μΌκ΄λμ§ μμ μ μμ΅λλ€.
μ ν리μΌμ΄μ λ‘€λ°±
μ΄μ μ± λ²μ μ΄ μκ²Όμ΅λλ€ 2.0.0 κ·Έλ¦¬κ³ λ°μ΄ν°λ² μ΄μ€ v2.
λ¨κ³ :
- μ ν리μΌμ΄μ
μ λ²μ μΌλ‘ λ‘€λ°±
1.0.0. - λ²μ
1.0.0λ°μ΄ν°λ² μ΄μ€μ μ΄μ μ¬μ©νμ§ μμ΅λλ€.surnameμ΄λ―λ‘ λ‘€λ°±μ΄ μ±κ³΅ν΄μΌ ν©λλ€.
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');μ€ν¬λ¦½νΈ μΆκ° surname.
μ£Όμ. μΆκ°νλ μ΄μλ NOT 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λ¨κ³: μ½λμμ last_name μ κ±°
μ± λ²μ : 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, XNUMXμ΄ μλ κ²½μ°, κ·Έλ μ§ μμ κ²½μ° -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;μ½λ λ³κ²½
λ©λͺ¨ per.: μ΄ λΈλ‘μ λν μ€λͺ
λ μμ±μκ° 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λ¨κ³: λ°μ΄ν°λ² μ΄μ€μμ last_name μ κ±°
μ± λ²μ : 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.0.0Ρv1λ°μ΄ν°λ² μ΄μ€ μ€ν€λ§(μ΄ μ΄λ¦ =last_name) - μ ν리μΌμ΄μ
λ²μ λ°°ν¬
2.0.0,λ°μ΄ν°λ₯Ό μ μ₯νλ κ³³last_nameΠΈsurname. μμ© νλ‘κ·Έλ¨μ λ€μμμ μ½μ΅λλ€.last_name. λ°μ΄ν°λ² μ΄μ€ λ²μ μ΄ λ€μκ³Ό κ°μ΅λλ€.v2λ€μκ³Ό κ°μ μ΄μ ν¬ν¨νλlast_nameκ³Όsurname. surnamelμ 볡μ¬λ³Έμ΄μμast_name. (μ°Έκ³ : μ΄ μ΄μλ nullμ΄ μλ μ μ½ μ‘°κ±΄μ΄ μμ΄μλ μ λ©λλ€.) - μ ν리μΌμ΄μ
λ²μ λ°°ν¬
3.0.0, λ°μ΄ν°λ§ μ μ₯ν©λλ€.surnameμ±μμ μ½μ΅λλ€. λ°μ΄ν°λ² μ΄μ€μ κ²½μ° λ§μ§λ§ λ§μ΄κ·Έλ μ΄μ μ΄ μ§ν μ€μ λλ€.last_nameΠ²surname. λν νκ³ NULL μλ μμ μ κ±°λ¨last_name. λ°μ΄ν°λ² μ΄μ€κ° νμ¬ λ²μ μ λλ€v3 - μ ν리μΌμ΄μ
λ²μ λ°°ν¬
4.0.0- μ½λλ λ³κ²½λμ§ μμ΅λλ€. λ°μ΄ν°λ² μ΄μ€ λ°°ν¬v4, μ κ±°last_name. μ¬κΈ°μμ λ°μ΄ν°λ² μ΄μ€μ λλ½λ μ μ½ μ‘°κ±΄μ μΆκ°ν μ μμ΅λλ€.
μ΄ μ κ·Ό λ°©μμ λ°λ₯΄λ©΄ λ°μ΄ν°λ² μ΄μ€/μ ν리μΌμ΄μ νΈνμ±μ μμμν€μ§ μκ³ νμ νλμ λ²μ μ λ‘€λ°±ν μ μμ΅λλ€.
μνΈ
μ΄ κΈ°μ¬μ μ¬μ©λ λͺ¨λ μ½λλ λ€μμμ μ¬μ©ν μ μμ΅λλ€. . μλλ μΆκ° μ€λͺ μ λλ€.
νλ‘μ νΈ
μ μ₯μλ₯Ό 볡μ νλ©΄ λ€μκ³Ό κ°μ ν΄λ ꡬ쑰λ₯Ό λ³Ό μ μμ΅λλ€.
βββ boot-flyway-v1 - 1.0.0 version of the app with v1 of the schema
βββ boot-flyway-v2 - 2.0.0 version of the app with v2 of the schema (backward-compatible - app can be rolled back)
βββ boot-flyway-v2-bad - 2.0.0.BAD version of the app with v2bad of the schema (backward-incompatible - app cannot be rolled back)
βββ boot-flyway-v3 - 3.0.0 version of the app with v3 of the schema (app can be rolled back)
βββ boot-flyway-v4 - 4.0.0 version of the app with v4 of the schema (app can be rolled back)μ€ν¬λ¦½νΈ
μλ μ€ν¬λ¦½νΈμ μ€λͺ λ μ€ν¬λ¦½νΈλ₯Ό μ€νν μ μμΌλ©°, μ΄λ λ°μ΄ν°λ² μ΄μ€μ λν μ΄μ λ²μ κ³Ό νΈνλλ λ³κ²½ μ¬νκ³Ό νΈνλμ§ μλ λ³κ²½ μ¬νμ 보μ¬μ€λλ€.
νμΈνλ €λ©΄ μ΄μ λ²μ κ³Ό νΈνλλ λ³κ²½ μ¬νμ΄ μλ κ²½μ°, λ¬λ¦¬λ€:
./scripts/scenario_backward_compatible.shκ·Έλ¦¬κ³ λ³΄κΈ° μν΄ μ΄μ λ²μ κ³Ό νΈνλμ§ μλ λ³κ²½ μ¬νμ΄ μλ κ²½μ°, λ¬λ¦¬λ€:
./scripts/scenario_backward_incompatible.shμ€νλ§ λΆνΈ μν μ΄λ κ²½λ‘
λͺ¨λ μμ λ λ€μμμ κ°μ Έμμ΅λλ€. Spring Boot Sample Flyway.
λΉμ μ μ΄ν΄λ³Ό μ μμ΅λλ€ http://localhost:8080/flyway, μ€ν¬λ¦½νΈ λͺ©λ‘μ΄ μμ΅λλ€.
μ΄ μμλ H2 μ½μλ ν¬ν¨λμ΄ μμ΅λλ€( http://localhost:8080/h2-console) λ°μ΄ν°λ² μ΄μ€ μνλ₯Ό λ³Ό μ μμ΅λλ€(κΈ°λ³Έ jdbc URLμ jdbc:h2:mem:testdb).
μΆκ°
λΈλ‘κ·Έμμ λ€λ₯Έ κΈ°μ¬λ μ½μ΄λ³΄μΈμ.
μΆμ² : habr.com
