Implantação e bancos de dados com tempo de inatividade zero

Implantação e bancos de dados com tempo de inatividade zero

Este artigo explica detalhadamente como resolver problemas de compatibilidade de banco de dados na implantação. Diremos a você o que pode acontecer com seus aplicativos de produção se você tentar implantar sem preparação prévia. Em seguida, passaremos pelos estágios do ciclo de vida do aplicativo que são necessários para ter tempo de inatividade zero (Aproximadamente. pista: mais longe - tempo de inatividade zero). O resultado de nossas operações será aplicar a alteração do banco de dados incompatível com versões anteriores de maneira compatível com versões anteriores.

Se quiser entender os exemplos de código do artigo, você pode encontrá-los em GitHub.

Introdução

Implantação com tempo de inatividade zero

Que místico implantação com tempo de inatividade zero? Você pode dizer que isso ocorre quando seu aplicativo é implantado de forma que você possa introduzir com êxito uma nova versão do aplicativo na produção, enquanto o usuário não percebe sua indisponibilidade. Do ponto de vista do usuário e da empresa, este é o melhor cenário de implantação possível porque permite a introdução de novos recursos e a correção de bugs sem interrupções.

Como conseguir isso? Existem várias maneiras, aqui está uma delas:

  • implantar a versão nº 1 do seu serviço
  • realizar uma migração de banco de dados
  • Implante a versão 2 do seu serviço em paralelo com a versão 1
  • assim que você perceber que a versão nº 2 funciona como deveria, remova a versão nº 1
  • pronto!

Fácil, não é? Infelizmente, não é tão simples e veremos isso em detalhes mais tarde. Agora vamos verificar outro processo de implantação bastante comum - implantação azul verde.

Você já ouviu falar implantação azul verde? O Cloud Foundry torna isso extremamente fácil. Basta olhar Este artigo, onde descrevemos isso com mais detalhes. Para resumir brevemente, vamos lembrá-lo de como fazer a implantação azul verde:

  • garantir que duas cópias do seu código de produção (“azul” e “verde”) funcionem;
  • direcionar todo o tráfego para o ambiente azul, ou seja, para que os URLs de produção apontem para lá;
  • implantar e testar todas as alterações de aplicativos em um ambiente ecológico;
  • mudar URLs do ambiente azul para verde

A implantação azul verde é uma abordagem que permite introduzir facilmente novos recursos sem se preocupar com a interrupção da produção. Isso se deve ao fato de que, mesmo que algo aconteça, você pode facilmente reverter para o ambiente anterior simplesmente “apertando um botão”.

Depois de ler tudo acima, você pode fazer a pergunta: O que o tempo de inatividade zero tem a ver com a implantação do Azul Verde?

Pois bem, eles têm muito em comum, pois manter duas cópias do mesmo ambiente exige o dobro do esforço para mantê-las. É por isso que algumas equipes afirmam Martin Fowler, siga uma variação desta abordagem:

Outra opção é usar o mesmo banco de dados, criando switches azul-verde para as camadas web e de domínio. Nessa abordagem, o banco de dados muitas vezes pode ser um problema, especialmente quando é necessário alterar seu esquema para suportar uma nova versão do software.

E aqui chegamos ao problema principal deste artigo. Banco de dados. Vamos dar uma outra olhada nesta frase.

realizar uma migração de banco de dados.

Agora você deve se perguntar: e se a alteração do banco de dados não for compatível com versões anteriores? Minha primeira versão do aplicativo não quebrará? Na verdade, é exatamente isso que vai acontecer...

Portanto, mesmo apesar dos enormes benefícios do tempo de inatividade zero/implantação azul verde, as empresas tendem a seguir o seguinte processo mais seguro para implantar seus aplicativos:

  • preparar um pacote com uma nova versão do aplicativo
  • encerrar um aplicativo em execução
  • execute scripts para migrar o banco de dados
  • implantar e lançar uma nova versão do aplicativo

Neste artigo, detalharemos como você pode trabalhar com seu banco de dados e código para aproveitar a implantação com tempo de inatividade zero.

Problemas de banco de dados

Se você tiver um aplicativo sem estado que não armazena dados no banco de dados, poderá obter uma implantação com tempo de inatividade zero imediatamente. Infelizmente, a maioria dos softwares precisa armazenar dados em algum lugar. É por isso que você deve pensar duas vezes antes de fazer qualquer alteração no circuito. Antes de entrarmos em detalhes sobre como alterar o esquema para que a implantação sem tempo de inatividade seja possível, vamos primeiro nos concentrar no esquema de controle de versão.

Esquema de versionamento

Neste artigo usaremos pista de pouso como uma ferramenta de controle de versão (Aproximadamente. Tradução: estamos falando de migrações de banco de dados). Naturalmente, também escreveremos um aplicativo Spring Boot que tenha suporte integrado ao Flyway e realizará a migração do esquema enquanto configura o contexto do aplicativo. Ao usar o Flyway, você pode armazenar scripts de migração na pasta de projetos (por padrão em classpath:db/migration). Aqui você pode ver um exemplo desses arquivos de migração

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

Neste exemplo vemos 4 scripts de migração que, se não forem executados anteriormente, serão executados um após o outro quando a aplicação for iniciada. Vejamos um dos arquivos (V1__init.sql) como um exemplo.

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

Tudo é perfeitamente autoexplicativo: você pode usar SQL para definir como seu banco de dados deve ser modificado. Para obter mais informações sobre Spring Boot e Flyway, confira Documentos de inicialização do Spring.

Ao usar uma ferramenta de controle de origem com Spring Boot, você obtém dois grandes benefícios:

  • você separa as alterações do banco de dados das alterações do código
  • A migração do banco de dados ocorre junto com a implementação do seu aplicativo, ou seja, seu processo de implantação é simplificado

Solução de problemas de banco de dados

Na próxima seção do artigo, nos concentraremos em examinar duas abordagens para alterações no banco de dados.

  • incompatibilidade com versões anteriores
  • compatibilidade com versões anteriores

O primeiro será considerado um aviso de que você não deve realizar uma implantação com tempo de inatividade zero sem preparação preliminar... O segundo oferece uma solução sobre como você pode realizar uma implantação sem tempo de inatividade e ao mesmo tempo manter a compatibilidade com versões anteriores.

Nosso projeto no qual estaremos trabalhando será um aplicativo Spring Boot Flyway simples que possui Person с first_name и last_name no banco de dados (Aproximadamente. tradução: Person é uma mesa e first_name и last_name - estes são os campos nele). Queremos renomear last_name в surname.

Suposições

Antes de entrarmos em detalhes, há algumas suposições que precisamos fazer sobre nossas aplicações. O principal resultado que queremos alcançar será um processo bastante simples.

A anotação. PRO-TIP de negócios. Simplificar processos pode economizar muito dinheiro em suporte (quanto mais pessoas você tiver trabalhando na sua empresa, mais dinheiro você poderá economizar)!

Não há necessidade de reverter o banco de dados

Isso simplifica o processo de implantação (algumas reversões de banco de dados são quase impossíveis, como a reversão de exclusão). Preferimos reverter apenas aplicativos. Dessa forma, mesmo que você tenha bancos de dados diferentes (por exemplo, SQL e NoSQL), seu pipeline de implantação terá a mesma aparência.

SEMPRE deve ser possível reverter o aplicativo uma versão (não mais)

A reversão só deve ser feita quando necessário. Se houver um bug na versão atual que não seja facilmente corrigido, poderemos reverter para a versão funcional mais recente. Presumimos que esta última versão de trabalho seja a anterior. Manter a compatibilidade do código e do banco de dados para mais de uma implementação seria extremamente difícil e caro.

Заметка. Para maior legibilidade, neste artigo iremos alterar a versão principal do aplicativo.

Passo 1: Estado Inicial

Versão do aplicativo: 1.0.0
Versão do banco de dados: v1

comentário

Este será o estado inicial do aplicativo.

Mudanças no banco de dados

Banco de dados contém 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');

Mudanças de código

O aplicativo armazena dados da Pessoa em 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
                + "]";
    }
}

Renomeação de coluna incompatível com versões anteriores

Vejamos um exemplo de como alterar o nome de uma coluna:

Atenção. O exemplo a seguir quebrará coisas intencionalmente. Mostramos isso para demonstrar o problema de compatibilidade de banco de dados.

Versão do aplicativo: 2.0.0.BAD

Versão do banco de dados: v2bad

comentário

As mudanças atuais NÃO nos permitem executar duas instâncias (antiga e nova) ao mesmo tempo. Assim, será difícil conseguir uma implementação com tempo de inatividade zero (se as suposições forem levadas em conta, é na verdade impossível).

Teste A/B

A situação atual é que temos uma versão do aplicativo 1.0.0, implantado em produção e banco de dados v1. Precisamos implantar uma segunda instância do aplicativo, versão 2.0.0.BADe atualize o banco de dados para v2bad.

Etapas:

  1. uma nova instância da versão do aplicativo é implantada 2.0.0.BADque atualiza o banco de dados para v2bad
  2. no banco de dados v2bad coluna last_name não existe mais - foi alterado para surname
  3. A atualização do banco de dados e do aplicativo foi bem-sucedida e algumas instâncias estão em execução 1.0.0, outros - em 2.0.0.BAD. Tudo está conectado ao banco de dados v2bad
  4. todas as instâncias da versão 1.0.0 começarão a gerar erros porque tentarão inserir dados na coluna last_nameque não existe mais
  5. todas as instâncias da versão 2.0.0.BAD funcionará sem problemas

Como você pode ver, se fizermos alterações incompatíveis com versões anteriores no banco de dados e no aplicativo, o teste A/B será impossível.

Reversão de aplicativo

Vamos supor que depois de tentar fazer a implantação A/B (Aproximadamente. per.: o autor provavelmente quis dizer testes A/B aqui) decidimos que precisamos reverter o aplicativo para a versão 1.0.0. Digamos que não queremos reverter o banco de dados.

Etapas:

  1. paramos a instância do aplicativo de versão 2.0.0.BAD
  2. o banco de dados ainda está v2bad
  3. desde a versão 1.0.0 não entende o que é surname, veremos erros
  4. o inferno começou, não podemos mais voltar

Como você pode ver, se fizermos alterações incompatíveis com versões anteriores no banco de dados e no aplicativo, não poderemos reverter para a versão anterior.

Logs de execução de script

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

Mudanças no banco de dados

Script de migração que renomeia last_name в surname

Script Flyway de origem:

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

Script que renomeia last_name.

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

Mudanças de código

Mudamos o nome do campo lastName em surname.

Renomeando uma coluna de maneira compatível com versões anteriores

Esta é a situação mais comum que podemos encontrar. Precisamos fazer mudanças incompatíveis com versões anteriores. Já provamos que, para uma implantação com tempo de inatividade zero, não devemos simplesmente aplicar a migração de banco de dados sem etapas adicionais. Nesta seção do artigo, realizaremos 3 implantações do aplicativo junto com migrações de banco de dados para alcançar o resultado desejado, mantendo a compatibilidade com versões anteriores.

A anotação. Lembre-se de que temos um banco de dados de versões v1. Contém colunas first_name и last_name. Temos que mudar last_name em surname. Também temos versão do aplicativo 1.0.0, que ainda não é usado surname.

Etapa 2: adicionar sobrenome

Versão do aplicativo: 2.0.0
Versão do banco de dados: v2

comentário

Ao adicionar uma nova coluna e copiar seu conteúdo, criamos alterações de banco de dados compatíveis com versões anteriores. Ao mesmo tempo, se revertermos o JAR ou tivermos um JAR antigo em execução, ele não será interrompido durante a execução.

Estamos lançando uma nova versão

Etapas:

  1. realizar uma migração de banco de dados para criar uma nova coluna surname. Agora sua versão do banco de dados v2
  2. copiar dados de last_name в surname. Notaque se você tiver muitos desses dados, considere a migração em lote!
  3. escreva o código onde eles são usados Ambos и novoE o velho coluna. Agora a versão do seu aplicativo 2.0.0
  4. leia o valor da coluna surname, Se não é null, ou de last_namese surname não especificado. Você pode excluir getLastName() do código, pois ele produzirá null ao reverter seu aplicativo de 3.0.0 para 2.0.0.

Se você estiver usando Spring Boot Flyway, essas duas etapas serão executadas durante a inicialização da versão 2.0.0 formulários. Se você executar a ferramenta de controle de versão do banco de dados manualmente, terá que fazer duas coisas diferentes para fazer isso (primeiro atualizar a versão do banco de dados manualmente e depois implantar o novo aplicativo).

Importante. Lembre-se de que a coluna recém-criada NÃO DEVERIA быть NÃO NULO. Se você fizer uma reversão, o aplicativo antigo não saberá sobre a nova coluna e não a instalará durante Insert. Mas se você adicionar essa restrição e seu banco de dados será v2, isso exigirá a configuração do valor da nova coluna. O que levará a violações de restrições.

Importante. Você deve remover o método getLastName(), porque na versão 3.0.0 Não há conceito de coluna no código last_name. Isso significa que null será definido lá. Você pode sair do método e adicionar verificações para null, mas uma solução muito melhor seria garantir que na lógica getSurname() você selecionou o valor correto diferente de zero.

Teste A/B

A situação atual é que temos uma versão do aplicativo 1.0.0, implantado em produção e o banco de dados em v1. Precisamos implantar uma segunda instância da versão do aplicativo 2.0.0que atualizará o banco de dados para v2.

Etapas:

  1. uma nova instância da versão do aplicativo é implantada 2.0.0que atualiza o banco de dados para v2
  2. entretanto, algumas solicitações foram processadas por instâncias de versão 1.0.0
  3. a atualização foi bem-sucedida e você tem várias instâncias em execução da versão do aplicativo 1.0.0 e outras versões 2.0.0. Todos se comunicam com o banco de dados em v2
  4. versão 1.0.0 não usa a coluna de sobrenome no banco de dados, mas a versão 2.0.0 usa. Eles não interferem entre si e não deve haver erros.
  5. versão 2.0.0 armazena dados na coluna antiga e na nova, garantindo compatibilidade com versões anteriores

Importante. Se você tiver alguma consulta que conte itens com base nos valores da coluna antiga/nova, lembre-se de que agora você tem valores duplicados (provavelmente eles ainda estão migrando). Por exemplo, se você quiser contar o número de usuários cujo sobrenome (qualquer que seja o nome da coluna) começou com a letra A, até que a migração de dados seja concluída (oldnew coluna), você poderá ter dados inconsistentes se consultar uma nova coluna.

Reversão de aplicativo

Agora temos versão do aplicativo 2.0.0 e banco de dados em v2.

Etapas:

  1. reverter seu aplicativo para a versão 1.0.0.
  2. versão 1.0.0 não usa coluna no banco de dados surname, então a reversão deve ser bem-sucedida

Mudanças no banco de dados

O banco de dados contém uma coluna chamada last_name.

Script de origem 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');

Adicionar script surname.

Atenção. Lembre-se de que você NÃO PODE ADICIONAR nenhuma restrição NOT NULL à coluna que está adicionando. Se você reverter o JAR, a versão antiga não terá ideia sobre a coluna adicionada e a definirá automaticamente como NULL. Se houver tal limitação, o aplicativo antigo simplesmente quebrará.

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

Mudanças de código

Armazenamos dados como last_namee em surname. Ao mesmo tempo, lemos de last_name, já que esta coluna é a mais relevante. Durante o processo de implantação, algumas solicitações podem ter sido processadas por uma instância de aplicação que ainda não foi atualizada.

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

Etapa 3: Removendo last_name do código

Versão do aplicativo: 3.0.0

Versão do banco de dados:v3

comentário

Observação por.: Aparentemente, no artigo original o autor copiou erroneamente o texto deste bloco da etapa 2. Nesta etapa, deverão ser feitas alterações no código da aplicação visando retirar a funcionalidade que utiliza a coluna last_name.

Ao adicionar uma nova coluna e copiar seu conteúdo, criamos alterações de banco de dados compatíveis com versões anteriores. Além disso, se revertermos o JAR ou tivermos um JAR antigo em execução, ele não será interrompido durante a execução.

Reversão de aplicativo

Atualmente temos versão do aplicativo 3.0.0 e banco de dados v3... Versão 3.0.0 não salva dados em last_name. Isto significa que em surname as informações mais atualizadas são armazenadas.

Etapas:

  1. reverter seu aplicativo para a versão 2.0.0.
  2. versão 2.0.0 usa e last_name и surname.
  3. versão 2.0.0 vai levar surname, se não for zero, caso contrário -last_name

Mudanças no banco de dados

Não há alterações estruturais no banco de dados. O seguinte script é executado para realizar a migração final dos dados antigos:

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

Mudanças de código

Observação por.: A descrição deste bloco também foi copiada erroneamente pelo autor da etapa 2. De acordo com a lógica do artigo, as alterações no código nesta etapa devem ter como objetivo retirar dele elementos que funcionam com a coluna last_name.

Armazenamos dados como last_namee em surname. Além disso, lemos na coluna last_name, por ser o mais relevante. Durante o processo de implantação, algumas solicitações podem ser processadas por uma instância que ainda não foi atualizada.

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

Etapa 4: Removendo last_name do banco de dados

Versão do aplicativo: 4.0.0

Versão do banco de dados: v4

comentário

Devido ao fato de que o código da versão 3.0.0 não usei a coluna last_name, nada de ruim acontecerá durante a execução se revertermos para 3.0.0 depois de remover uma coluna do banco de dados.

Logs de execução de script

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

Mudanças no banco de dados

Em relação v3 apenas removemos a coluna last_name e adicione restrições ausentes.

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

Mudanças de código

Não há alterações no código.

Jogar aviator online grátis: hack aviator funciona

Aplicamos com êxito uma alteração de nome de coluna incompatível com versões anteriores, executando várias implantações compatíveis com versões anteriores. Abaixo segue um resumo das ações realizadas:

  1. implantação da versão do aplicativo 1.0.0 с v1 esquema do banco de dados (nome da coluna = last_name)
  2. implantação da versão do aplicativo 2.0.0, que armazena dados em last_name и surname. O aplicativo lê de last_name. O banco de dados está na versão v2contendo colunas como last_nameE surname. surname é uma cópia de last_name. (NOTA: Esta coluna não deve ter uma restrição não nula)
  3. implantação da versão do aplicativo 3.0.0, que armazena apenas dados em surname e lê o sobrenome. Quanto ao banco de dados, a última migração está ocorrendo last_name в surname. Também uma limitação NÃO NULO removido de last_name. O banco de dados agora está na versão v3
  4. implantação da versão do aplicativo 4.0.0 - nenhuma alteração é feita no código. Implantação de banco de dados v4, que remove last_name. Aqui você pode adicionar quaisquer restrições ausentes ao banco de dados.

Seguindo essa abordagem, você sempre pode reverter uma versão sem quebrar a compatibilidade do banco de dados/aplicativo.

código

Todo o código usado neste artigo está disponível em Github. Abaixo está uma descrição adicional.

Projetos

Após clonar o repositório, você verá a seguinte estrutura de pastas.

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

Você pode executar os scripts descritos nos scripts abaixo, que demonstrarão alterações compatíveis e incompatíveis com versões anteriores no banco de dados.

Ver o caso com alterações compatíveis com versões anteriores, correr:

./scripts/scenario_backward_compatible.sh

E para ver caso com alterações incompatíveis com versões anteriores, correr:

./scripts/scenario_backward_incompatible.sh

Amostra de Flyway de inicialização de primavera

Todos os exemplos são retirados de Spring Boot Sample Flyway.

Você pode dar uma olhada http://localhost:8080/flyway, há uma lista de scripts.

Este exemplo também inclui o console H2 (em http://localhost:8080/h2-console) para que você possa visualizar o status do banco de dados (o URL jdbc padrão é jdbc:h2:mem:testdb).

adicionalmente

Leia também outros artigos em nosso blog:

Fonte: habr.com

Adicionar um comentário