Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Laravel 5.5 Consolidar migrações com banco de dados de produção


Depois de algumas tentativas de solução excessivamente projetadas e inteligentes, acho que o seguinte é uma solução viável para o problema.

tl; dr:
  • Migrações de Bookend em ambos os lados das migrações que criam o esquema do nada.
  • Atualizar projeto.
  • Migre.
  • Exclua os bookends e todas as migrações anteriores.
  • Excluir registros de migrations tabela.

O primeiro bookend renomeia as tabelas afetadas. O segundo bookend copia os dados das tabelas renomeadas para as tabelas novas e, em seguida, exclui as tabelas renomeadas.

Observação:você pode fazer o que quiser dentro dos suportes para livros, isso é apenas o mínimo.

Então, digamos que você tenha algo como o seguinte para migrações:
  • 2017_09_05_000000_create_some_table.php
  • 2017_09_05_000001_add_field_x_to_some_table.php
  • 2017_09_05_000002_add_field_y_to_some_table.php
  • 2017_09_05_000003_add_field_z_to_some_table.php

Criaríamos outra migração:
  • 2017_09_05_000004_pre_refresh.php

Criaríamos outra migração com base no conhecimento que temos agora:
  • 2017_09_05_000005_create_some_table.php

Criaríamos o último bookend, onde ocorrerá a migração de dados:
  • 2017_09_05_000006_post_refresh.php

As primeiras quatro migrações não serão executadas porque já foram.
/** 2017_09_05_000004_pre_refresh.php */
class PreRefresh extends Migration
{
    public function up()
    {
        $prefix = 'zz_';
        $tablesToRename = [
            'foos',
            'bars'
        ];

        foreach($tablesToRename as $table) {
            Schema::rename($table, $prefix . $table);
        }
    }
}

Não há necessidade de um down, porque este é um negócio de um tiro. Isso será executado primeiro, o que deve resultar na renomeação de todas as tabelas listadas na matriz. Em seguida, as migrações consolidadas (otimizadas) serão executadas.
/** 2017_09_05_000006_post_refresh.php */
class PostRefresh extends Migration
{
    public function up()
    {
        // Do what you need to do.
        // If you cannot use your models, just use DB::table() commands.

        $foos = DB::table('zz_foos')->get();
        foreach ($foos as $foo) {
            DB::table('foo')->insert([
                    'id'         => $foo->id,
                    'created_at' => $foo->created_at,
                    'updated_at' => $foo->updated_at
                ]);
        }

        $bars = DB::table('zz_bars')->get();
        foreach ($bars as $bar) {
            DB::table('bar')->insert([
                    'id'         => $bar->id,
                    'created_at' => $bar->created_at,
                    'updated_at' => $bar->updated_at,
                    'foo_id'     => $bar->foo_id
                ]);
        }

        // Tear down.
        $prefix = 'zz_';
        $tablesToRename = [
            'foo',
            'bar'
        ];

        foreach ($tablesToRename as $table) {
            DB::statement('SET FOREIGN_KEY_CHECKS=0');
            Schema::dropIfExists($prefix . $table);
            DB::statement('SET FOREIGN_KEY_CHECKS=1');
        }
    }
}

Depois de executar isso, você pode excluir todas as suas migrações do pre_refresh e anterior. Assim como o post_refresh . Então você pode ir para as migrations table e exclua as entradas para essas migrações.

A exclusão das entradas não é totalmente necessária, mas se você migrate:rollback você receberá mensagens de erro informando que a migração não pode ser encontrada.

Advertências

  1. Se a arquitetura não for modular por design, pode ser bastante complicada. No entanto, se você separou seu código em serviços, parece ser um pouco mais fácil.
  2. O tratamento de erros do Laravel e as mensagens durante as migrações são muito limitados; portanto, a depuração pode ser difícil.
  3. Recomendamos começar com as tabelas mais estáveis ​​em seu aplicativo/serviço. Além disso, começar com aqueles que são fundamentais para seu aplicativo também pode ser benéfico.

Nota:Quando eu realmente fizer isso em produção, não apenas no meu local (repetidamente), e se não houver uma resposta melhor, aceitarei isso.

Considerações


Se você estiver dividindo seu aplicativo em provedores de serviços com migrações discretas, poderá comentar o provedor de serviços em /config/app quando você executa as migrações. Dessa forma, você cria um lote para o serviço agora com linha de base. Então, digamos que você tenha as seguintes migrações, onde cada letra representa uma migração e cada letra duplicada representa o mesmo serviço:
  • A
  • B
  • C
  • A
  • C
  • B
  • A

Após consolidar o serviço A:
  • B
  • C
  • C
  • B
  • A

Após consolidar B:
  • C
  • C
  • A
  • B

Após consolidar C:
  • A
  • B
  • C

atualizar

54 migrações para 27 até agora. Eu até tirei algumas alterações de esquema de grandes up() e down() métodos e torná-los migrações separadas. O bom efeito colateral aqui são os lotes. Eu migrei começando com as tabelas base nas quais todo o resto é suportado; portanto, reverter é mais serviço por serviço.