【问题标题】:Can I import a mysql dump to a laravel migration?我可以将 mysql 转储导入 laravel 迁移吗?
【发布时间】:2014-01-23 11:56:36
【问题描述】:

我有一个完整的数据库,需要创建迁移。我想一定有办法从转储中做到这一点,但不确定。有什么方法可以自动或至少更容易地完成这项任务吗?

【问题讨论】:

    标签: laravel


    【解决方案1】:

    你可以像这样在 Laravel 中导入转储:

    DB::unprepared(file_get_contents('full/path/to/dump.sql'));
    

    如果我要重构现有应用程序,我会花时间从头开始编写迁移,将转储导入不同的表(或不同的数据库,如果表名相同),然后将内容导入到通过种子的新结构。

    【讨论】:

    • 如果文件太大而无法放入内存怎么办?
    • 这完全是一个不同的问题。您可以增加 PHP 的 ini 文件中的内存限制,或者像这样在播种机上以编程方式进行:ini_set('memory_limit', '-1')
    • 是的,这是一个不同的问题,但 file_get_contents 仍然会因为“太大”的文件而失败,就像许多千兆字节一样。我会使用你的方法,但使用 fopen 和 fgets。 phpMyAdmin 导出可以用“INSERT INTO”分块
    【解决方案2】:

    我正在写我的答案,因为这可能对使用新 laravel 8 的人有所帮助。

    在 laravel 8 中,可以使用 SQL(.dump) 文件转储 SQL 和运行迁移。详情请参考以下链接。

    https://laravel.com/docs/8.x/migrations#squashing-migrations

    php artisan schema:dump
    
    // Dump the current database schema and prune all existing migrations...
    php artisan schema:dump --prune
    

    schema:dump 将在数据库> 架构下创建新目录,并且 SQL 转储将存储在那里。 之后,当您尝试首先迁移时,它将从架构运行转储文件,然后运行任何待处理的迁移。

    【讨论】:

    • 我最初提出问题 7 年后。 Laravel 8 正确使用 schema:dump
    【解决方案3】:

    另一种选择是直接使用 PDO:

    use Illuminate\Support\Facades\DB;
    use Illuminate\Support\Facades\File;
    
    $sql_dump = File::get('/path/to/file.sql');
    DB::connection()->getPdo()->exec($sql_dump);
    

    【讨论】:

    • 指定您建议使用的特定File 类将非常有用。
    • 使用该选项时,可以使用file_get_contents函数获取sql转储。还要确保不要使用 LOCK TABLES,否则 Laravel 写入迁移表时会出错
    【解决方案4】:

    Laravel 文章提供的从现有数据库表生成迁移文件的简单解决方案。

    试试:https://laravelarticle.com/laravel-migration-generator-online

    【讨论】:

    • 问题完全是另外一回事!
    • 是的,它离题了,但这正是我需要的...将现有架构导入迁移。
    【解决方案5】:

    我有一个完整的数据库,需要创建迁移。我想一定有办法从转储中做到这一点,但不确定。有什么方法可以自动完成或至少更容易完成这项任务吗?

    不是自动的,但我们使用DB::unprepared() 在迁移中运行转储。您可以使用file_get_contents.sql 文件导入,因此不必担心转义整个转储的" 标记...

    <?php
    
    use Illuminate\Database\Migrations\Migration;
    
    class ImportDump extends Migration {
    
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            DB::unprepared("YOUR SQL DUMP HERE");
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
    
        }
    
    }
    

    【讨论】:

    • 此解决方案适用于具有多个字符集和排序规则的 MySQL 数据库。
    • 当使用带有 phpmyadmin 的 sql 文件 exportet 时,我必须使用 DB::unprepared(),因为 DB::statement() 会抛出 sql syntax error 。查看 tbuteler 的回答
    • @shock_gone_wild 很好,我不知道它存在。修改了答案。
    【解决方案6】:

    这个问题已经回答了,但是最近在一个项目中,提供的答案不再满足我的需求。它也不会导入整个数据库转储,而是导入一个(大)表。我觉得我应该和你分享。

    问题是,我想在我的 artisan:migrate 操作期间导入一个相当大的表(邮政编码列表)。 DB::unprepared($dump) 的解决方案花费了很长时间,我找到了一个更快的替代方案。

    只需将表导出为 CSV 并在迁移的 up() 函数中使用以下代码。

        // i had to str_replace the backslash on windows dev system... but works on linux, too
        $filename = str_replace("\\", "/", storage_path('path/in/storage/to/your/file.csv'));
    
        $query = "LOAD DATA LOCAL INFILE '".$filename."' INTO TABLE yourtable
            FIELDS TERMINATED BY '\t'
            ENCLOSED BY ''
            LINES TERMINATED BY '\n'
            IGNORE 0 LINES
            (col1,col2,...);";
    
        DB::unprepared($query);
    

    只需根据需要更新查询。当然,您应该确保带有 cols 的表 'col1'、'col2' 等......存在。我在导入文件之前创建了它。使用 Schema::create()...

    如果您遇到以下错误消息:

    PDO::exec(): LOAD DATA LOCAL INFILE forbidden
    

    有一种方法可以消除此消息:虽然它没有真正记录在案,但您可以在 config/database.php 文件中添加一个“选项”键。例如我的看起来像这样:

            'mysql' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', 'localhost'),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
            'options'   => array(
                PDO::MYSQL_ATTR_LOCAL_INFILE => true,
            )
    

    注意:我目前使用的是 laravel 5,但它也应该适用于 laravel 4。

    【讨论】:

    • 这可能是最好的绝对方法,尤其是当数据库变得庞大时
    • 这是一个很好的解决方案,只要数据库服务器与网络服务器存在于同一台机器上,否则LOAD DATA LOCAL INFILE会失败。
    • @rahmanisback 不,文件路径必须是数据库服务器上文件的路径,无论该数据库在哪里。因此,如果您将转储放在远程数据库上的 /tmp/dump.sql 中并使用该路径调用它,它将起作用。
    • @EllertvanKoperen 是的,但迁移脚本是应用程序代码的一部分,永远不应该假设任何代码文件都会进入数据库服务器。此外,迁移作为一个术语,应该与应用程序代码捆绑在一起,而不是单独上传到数据库服务器,以防数据库服务器与 Web 服务器不同。一个人应该在没有数据库和应用程序托管位置的初始前提下进行编码。
    • @rahmanisback 你对一个人应该假设和不假设什么是正确的。然而,远程恢复确实有效,并且在某些情况下是一个非常重要的节省时间。
    【解决方案7】:

    在 Laravel 5.2 中为我工作的另一个解决方案:

    DB::unprepared(File::get('full/path/to/dump.sql'));

    【讨论】:

    • 有趣而优雅的方法应该可行,但不适用于我的情况。想知道更多会很有趣。
    • 如果你使用 phpmyadmin 的转储,它通常包含如下选项:SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; 摆脱它,它会工作
    【解决方案8】:

    Laravel 无法做到这一点,但我认为这会有所帮助:Laravel migration generator

    它根据现有表生成迁移。

    【讨论】:

    【解决方案9】:

    您可以使用 https://github.com/XCMer/larry-four-generator 直接从数据库创建 laravel 迁移和模型

    安装包后执行以下代码

    php artisan larry:fromdb
    

    【讨论】:

      【解决方案10】:

      我最近站在同样的问题面前。我不想专门为此安装一个包,所以我决定写一个小工具来帮助我和其他人;)

      这里是链接: http://laravel.stonelab.ch/sql-seeder-converter/

      如果您有任何改进建议或问题,您可以在这里发表评论: http://www.stonelab.ch/en/sql-to-laravel-seeder-converter/

      【讨论】:

      • 我检测到输出中缺少逗号,现在已修复。
      【解决方案11】:

      您可以使用 Raahul/Larryfour 包,Laravel 4 的模型和迁移生成器

      Raahul/Larryfour Package

      安装后,您可以使用命令行从现有数据库创建迁移,如下所示:

      php artisan raahul:fromdb --only yourdatabase
      

      您会在 app/migrations/ 文件夹中找到迁移

      【讨论】:

        【解决方案12】:

        如果您可以转储到 CSV: 一些通用数据表(国家、州、邮政编码)的替代方案,不是通过迁移而是通过播种机。尽管您可以在迁移文件中以相同的方式执行此操作。

        在你的种子文件中:

            public function run()
            {
                $this->insertFromCsvFile('countries', 'path/to/countries.csv');
                $this->insertFromCsvFile('states', 'path/to/states.csv');
                $this->insertFromCsvFile('postal_codes', 'path/to/postal_codes.csv');
            }
        
            private function insertFromCsvFile($tableName, $filePath)
            {
                if( !file_exists($filePath) ){
                    echo 'File Not Found: '.$filePath."\r\n";
                    return;
                }
                $headers = $rows = [];
                $file = fopen( $filePath, 'r' );
                while( ( $line = fgetcsv( $file ) ) !== false ){
        
                    // The first row should be header values that match column names.
                    if( empty( $headers ) ){
                        $headers = explode( ',', implode( ',', $line ) );
                        continue;
                    }
        
                    $row = array_combine( $headers, $line );
                    foreach( $row as &$val ) if( $val === 'NULL' ) $val = null;
                    $rows[] = $row;
        
                    // Adjust based on memory constraints.
                    if( count($rows) === 500 ){
                        DB::table( $tableName )->insert($rows);
                        $rows = [];
                    }
                }
                fclose( $filePath );
        
                if( count($rows) ) DB::table( $tableName )->insert($rows);
            }
        

        运行播种机:php artisan db:seed --class=GenericTableSeeder

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-27
          • 2017-03-20
          相关资源
          最近更新 更多