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

Posted

技术标签:

【中文标题】Laravel 5.5 使用生产数据库整合迁移【英文标题】:Laravel 5.5 Consolidate migrations w/ production database 【发布时间】:2018-02-13 19:33:26 【问题描述】:

希望我能解释清楚。

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

认为这样会起作用:

    将所有生产表迁移到所需状态。 将所有迁移文件合并到所需的最少文件数中。 清除迁移表。 运行迁移或填充迁移表。

我之所以愿意这样做的部分原因是因为我想以尽可能干净的迁移集公开一些服务提供商。

困难的版本可能是:

    备份或复制表格。 运行迁移。 编写并运行脚本来填充“干净”的表。

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

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

【问题讨论】:

那么,您的 db 结构已退出旧版,现在您已经对 db 进行了更改,并且还想将这些更改更新到生产环境中? 备份您的数据库并运行php artisan migrate:refresh 命令。 您还可以进行迁移,使用所需列更改当前表并迁移它。 我可能没有完全理解。我有一个 production 数据库,其中包含大约 50 多个迁移文件 - 一些小的更改,一些大的更改。如果我合并,所需的迁移次数将更像是 12 次左右。我想整合迁移文件,但仍然能够在生产环境中执行 migrate:rollback - 我不会这样做。 这需要一些工作,因为您不想从实时数据库中删除数据。合并您的文件,然后从迁移表中删除已删除的迁移文件。 【参考方案1】:

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

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

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

【讨论】:

不确定这个“你做错了”的答案是否有帮助。我知道它应该如何工作;多年来一直这样做。我想为开发人员社区提供一个包......他们不需要知道导致最新版本的数据库架构更改。障碍是如何做到这一点并维护生产数据,这是唯一具有架构的数据库,同时允许我使用我提供给社区的相同代码库。 迁移既用于在部署期间推进生产,也用于两种开发场景:设置种子本地数据库,以及引导功能/集成测试。当你有成百上千的迁移时,很遗憾地清理是必要的。在实践中,企业经常在表或列只是暂时存在的情况下进行实验。【参考方案2】:

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

tl;博士:

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

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

注意:你可以在书挡里做任何你想做的事,这只是最低限度。

所以,让我们假设您的迁移如下所示:

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

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

/** 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 表并删除这些迁移的条目。

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

注意事项

    如果架构在设计上不是模块化的,那么它可能会非常麻烦。但是,如果您已将代码分成服务,它似乎会更容易一些。 迁移期间的 Laravel 错误处理和消息非常有限;因此,调试可能会很困难。 强烈建议从应用/服务中最稳定的表开始。此外,从那些对您的应用至关重要的内容开始也可能会证明是有益的。

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

注意事项

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

一个 B C 一个 C B 一个

合并服务 A 后:

B C C B 一个

合并B后:

C C 一个 B

合并C后:

一个 B C

更新

到目前为止,从 54 次迁移到 27 次。我什至从大型 up()down() 方法中提取了一些 Schema 更改,并将它们单独迁移。这里很好的副作用是批次。我从支持其他所有内容的基表开始迁移;因此,回滚更多的是服务。

【讨论】:

【参考方案3】:

您可以使用库 "xethron/migrations-generator" 。这是repo。

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

在at laracast找到一些关于这个的讨论。

【讨论】:

或支持 Laravel 8 的 github.com/kitloong/laravel-migrations-generator【参考方案4】:

我在寻找有关组合(laravel 称之为 squashing)迁移的信息时发现了这个问题。我想我会放弃一个答案,以供将来寻找此信息的任何人使用。

Laravel 8.0 现在允许这样做:

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

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

您可以在这里阅读更多内容Laravel 8.0 Squash Database Migrations

【讨论】:

以上是关于Laravel 5.5 使用生产数据库整合迁移的主要内容,如果未能解决你的问题,请参考以下文章

如何在 laravel 5.5 迁移中将 DB::unprepared() 用于 mysql 函数和存储过程

使用 Laravel 5 中的 --force 进行生产时,数据库卡在使用播种机迁移

LARAVEL 5.5 - 使用 Eloquent 模型将数据从 FORM 插入数据库

生产环境中的 Laravel 4.x 迁移

laravel跟书练习笔记2

Laravel 在生产服务器上迁移