Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Laravel 5.5 Konsoliduj migracje z produkcyjną bazą danych

Po kilku nadmiernie przemyślanych i zbyt sprytnych próbach rozwiązania, myślę, że poniższe jest wykonalnym rozwiązaniem problemu.

tl;dr:

  • Migracje Bookend po obu stronach migracji, które budują schemat z niczego.
  • Zaktualizuj projekt.
  • Migracja.
  • Usuń podpórki i wszystkie poprzednie migracje.
  • Usuń rekordy z migrations stół.

Pierwsza podpórka do książki zmienia nazwy stołów, których to dotyczy. Druga podpórka kopiuje dane z tabel ze zmienioną nazwą do nowych tabel, a następnie usuwa tabele ze zmienioną nazwą.

Uwaga:w podpórkach do książek możesz robić, co chcesz, to tylko minimum.

Załóżmy więc, że w przypadku migracji powiedzmy coś takiego:

  • 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

Utworzylibyśmy kolejną migrację:

  • 2017_09_05_000004_pre_refresh.php

Stworzylibyśmy kolejną migrację w oparciu o wiedzę, którą mamy teraz:

  • 2017_09_05_000005_create_some_table.php

Stworzylibyśmy ostatnią podpórkę, w której nastąpi migracja danych:

  • 2017_09_05_000006_post_refresh.php

Pierwsze cztery migracje nie zostaną uruchomione, ponieważ już zostały.

/** 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);
        }
    }
}

Nie ma potrzeby obniżania, ponieważ jest to transakcja jednorazowa. To zostanie uruchomione jako pierwsze, co powinno spowodować zmianę nazwy wszystkich tabel wymienionych w tablicy. Następnie zostanie uruchomiona skonsolidowana (zoptymalizowana) migracja.

/** 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');
        }
    }
}

Po uruchomieniu możesz usunąć wszystkie migracje z pre_refresh i wcześniejsze. Jak również post_refresh . Następnie możesz przejść do migrations tabeli i usuń wpisy dla tych migracji.

Usunięcie wpisów nie jest całkowicie konieczne, ale jeśli migrate:rollback otrzymasz komunikaty o błędach informujące, że nie można znaleźć migracji.

Ostrzeżenia

  1. Jeśli architektura nie jest z założenia modułowa, może być dość nieporęczna. Jeśli jednak podzieliłeś swój kod na usługi, wydaje się to trochę łatwiejsze.
  2. Obsługa błędów Laravela i komunikaty podczas migracji są bardzo ograniczone; więc debugowanie może być trudne.
  3. Zdecydowanie zalecamy rozpoczęcie od najbardziej stabilnych tabel w Twojej aplikacji/usługi. Co więcej, rozpoczęcie od tych, które są fundamentalne dla Twojej aplikacji, może również okazać się korzystne.

Uwaga:kiedy faktycznie robię to w środowisku produkcyjnym, a nie tylko w moim lokalnym (w kółko) i jeśli nie ma lepszej odpowiedzi, zaakceptuję to.

Rozważania

Jeśli dzielisz swoją aplikację na dostawców usług za pomocą dyskretnych migracji, możesz zakomentować dostawcę usług w /config/app po uruchomieniu migracji. W ten sposób utworzysz partię dla usługi z podstawową wartością. Załóżmy więc, że masz następujące migracje, w których każda litera reprezentuje migrację, a każda zduplikowana litera reprezentuje tę samą usługę:

  • A
  • B
  • C
  • A
  • C
  • B
  • A

Po konsolidacji usługi A:

  • B
  • C
  • C
  • B
  • A

Po konsolidacji B:

  • C
  • C
  • A
  • B

Po konsolidacji C:

  • A
  • B
  • C

aktualizacja

54 migracje do 27 dotychczas. Wyciągnąłem nawet kilka zmian schematu z dużego up() i down() metody i uczynić je oddzielnymi migracjami. Miłym efektem ubocznym są tu partie. Przeprowadziłem migrację, zaczynając od tabel podstawowych, na których obsługiwane jest wszystko inne; dlatego wycofywanie to bardziej usługa według usługi.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Eksportowanie tabeli do CSV za pomocą przycisku php

  2. Jak wyłączyć SHOW OSTRZEŻENIA w trybie hibernacji?

  3. Czy konieczne jest użycie mysql_real_escape_string(), gdy magic_quotes_gpc jest włączone?

  4. Indeks MySQL spowalnia zapytanie

  5. Architektura dla bezpieczeństwa:przewodnik po MySQL