Laravel 5.5 使用生产数据库整合迁移

Laravel 5.5 Consolidate migrations w/ production database

希望我能解释清楚。

我有一个 Laravel 应用程序已投入生产一分钟。所以,我有一堆有很多变化的迁移文件。我想在不丢失数据库的情况下整合这些迁移文件。

认为这样可行的方式:

  1. 将所有生产 table 迁移到所需状态。
  2. 将所有迁移文件合并为所需的最少数量的文件。
  3. 清除迁移 table。
  4. 运行 迁移或填充迁移 table。

我想这样做的部分原因是因为我想让一些服务提供商 public 拥有尽可能干净的迁移集。

困难的版本可能是:

  1. 备份或复制 tables.
  2. 运行 迁移。
  3. 编写 运行 脚本来填充 "clean" tables.

只是希望有比这更简单的方法。

编辑(来自评论):我有一个生产数据库,其中包含大约 50 多个迁移文件 - 一些小改动,一些大改动。如果我合并,所需的迁移数量大约为 12 次左右。我想合并迁移文件,但仍然能够在生产环境中执行 migrate:rollback - 但我不会。

看来你做错了。通常你不应该触及你的迁移,所以没有必要合并它们。特别是如果您将代码推送到生产服务器中,则根本不应该触摸。

总而言之 - 迁移是为了帮助您保持数据库架构应有的样子,但如果您想使用它们、合并它们或重建它们,没有人会阻止您,但如果您犯了错误,您可以轻易打破东西。

进行多次迁移并进行少量更改并没有错 - 这就是它的工作原理,您对 PHP 文件进行更改,对架构进行更改。

经过几次过度设计和过于聪明的解决方案尝试,我认为以下是解决问题的可行方案。

tl;博士:

  • 从无到有构建架构的迁移两侧的书挡迁移。
  • 更新项目。
  • 迁移。
  • 删除书挡和所有以前的迁移。
  • migrations table 中删除记录。

第一个书挡重命名了受影响的 table。第二个书立将数据从重命名的 tables 复制到新的 tables,然后删除重命名的 tables。

注意:您可以在书挡内随心所欲,这只是最低限度。

那么,让我们假设您使用以下类似的迁移方式:

  • 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

我们将创建另一个迁移:

  • 2017_09_05_000004_pre_refresh.php

我们将根据现有知识创建另一个迁移:

  • 2017_09_05_000005_create_some_table.php

我们将创建最后一个书挡,其中将发生数据迁移:

  • 2017_09_05_000006_post_refresh.php

前四次迁移不会 运行 因为它们已经发生了。

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

不需要降价,因为这是一次性交易。这将首先 运行,这将导致数组中列出的所有 table 被重命名。然后合并(优化)迁移将 运行.

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

在 运行 之后,您可以删除 pre_refresh 及之前的所有迁移。以及post_refresh。然后您可以进入 migrations table 并删除这些迁移的条目。

删除条目并非完全必要,但如果您migrate:rollback您将收到错误消息,指出无法找到迁移。

注意事项

  1. 如果架构在设计上不是模块化的,它可能会非常麻烦。但是,如果您将代码分离到服务中,它似乎会更容易一些。
  2. Laravel 迁移期间的错误处理和消息非常有限;因此,调试可能很困难。
  3. 强烈建议从 app/service 中最多的 table table 开始。此外,从那些对您的应用程序来说是基础的开始也可能被证明是有益的。

注意:当我实际在生产中这样做时,不仅仅是我的本地(一遍又一遍),如果没有更好的答案,那么我会接受这个。

注意事项

如果您通过谨慎的迁移将您的应用程序分解为服务提供商,那么您可以在 运行 迁移时在 /config/app 中注释掉服务提供商。这样您就可以为现在的基线服务创建一个批处理。因此,假设您有以下迁移,其中每个字母代表一个迁移,每个重复的字母代表相同的服务:

  • 一个
  • B
  • C
  • 一个
  • C
  • B
  • 一个

整合服务A后:

  • B
  • C
  • C
  • B
  • 一个

合并B后:

  • C
  • C
  • 一个
  • B

巩固C后:

  • 一个
  • B
  • C

更新

到目前为止,54 次迁移减少到 27 次。我什至从大型 up()down() 方法中提取了一些架构更改,并将它们分开迁移。这里好的副作用是批处理。我从基础 tables 开始迁移,其他一切都基于该基础得到支持;因此,回滚是一个服务一个服务。

您可以使用库“xethron/migrations-generator”。这是 repo.

安装后,基本使用: php artisan migrate:generate

找到一些关于此的讨论at laracast

我在查找有关合并(laravel 称之为压缩)迁移的信息时发现了这个问题。我想我会为将来寻找此信息的任何人提供答案。

Laravel 8.0 现在允许:

./artisan schema:dump 同时使用您的数据库 cli 客户端将数据库模式转储导出到 laravel 的 database/schema 文件夹中。

如果目标数据库上 运行 没有迁移,以后对 ./artisan migrate 的调用将首先执行架构文件,然后它会选择并 运行 最后一次之后的所有迁移一个存储在架构转储文件中。

您可以在此处阅读更多内容Laravel 8.0 Squash Database Migrations