如何在 Laravel 迁移中使用多个数据库设置外键约束

Posted

技术标签:

【中文标题】如何在 Laravel 迁移中使用多个数据库设置外键约束【英文标题】:How do you set Foreign Key Constraint in Laravel Migration using Multiple Databases 【发布时间】:2021-12-05 21:33:09 【问题描述】:

我目前正在处理一个需要使用多个数据库的项目。 在我的 .env 文件中,我有以下数据库变量:

DB_CONNECTION=mysql
DB_ONE_NAME=db1

DB_CONNECTION_TWO=mysql2
DB_TWO_NAME=db2

在我的 config/database.php 文件中,我有以下参考:

'mysql' => [
        'driver' => 'mysql',
        'url' => env('DATABASE_URL'),
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_ONE_NAME', 'db1'),
        'username' => env('DB_USERNAME', 'user'),
        'password' => env('DB_PASSWORD', 'root'),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix' => '',
        'prefix_indexes' => true,
        'strict' => true,
        'engine' => 'InnoDB',
        'options' => extension_loaded('pdo_mysql') ? array_filter([
            PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
        ]) : [],
    ],

'mysql2' => [
        'driver' => 'mysql',
        'url' => env('DATABASE_URL'),
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_TWO_NAME', 'db2'),
        'username' => env('DB_USERNAME', 'user'),
        'password' => env('DB_PASSWORD', 'root'),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix' => '',
        'prefix_indexes' => true,
        'strict' => true,
        'engine' => 'InnoDB',
        'options' => extension_loaded('pdo_mysql') ? array_filter([
            PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
        ]) : [],
    ],

在我的第一个迁移文件中,我有这个:

<?php

    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

    class CreateUsersTable extends Migration
    
  
      public function up()
      
        Schema::connection('mysql')->create('users', function (Blueprint $table) 
          $table->id();
          $table->string('name');
          $table->string('email')->unique();
          $table->string('username')->unique();
          $table->timestamps();

          $table->index('id');

    );



    public function down()
    
      Schema::connection('mysql')->dropIfExists('users');
    

在第二个迁移表中我有这个:

<?php

    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

    class CreateProjectsTable extends Migration
    
  
      public function up()
      
        Schema::connection('mysql2')->create('projects', function (Blueprint $table) 
          $table->id();
          $table->foreignId('user_id')->nullable()->constrained('mysql.users')->onDelete('set null');
          $table->string('name')->unique();
          $table->timestamps();

          $table->index(['id', 'user_id']);

    );



    public function down()
    
      Schema::connection('mysql2')->dropIfExists('projects');
    

我做错了什么? 我检查了任何重复的文件,但找不到任何错误。

同样,我最近在我的机器上将 PHP 和 MYSQL 都升级到了它们的最新版本。在 Laravel 项目上工作所需的所有扩展都已正确安装。

但是,我仍然收到此错误:

SQLSTATE[HY000]: General error: 1005 Can't create table `db2`.`projects` (errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter table `projects` add constraint `projects_user_id_foreign` foreign key (`user_id`) references `mysql`.`users` (`id`) on delete set null)

另外,当我运行这个命令时,

php artisan migrate --pretend

或者

php artisan migrate

我仍然遇到同样的错误。

我也试过用这个:

$table->unsignedBigInteger('user_id')->nullable();
$table->foreign('user_id')->references('id')->on('mysql.users')->onDelete('set null');

但没有任何效果。 还有其他方法可以解决这个问题吗? 如果有,请给我建议。 感谢您的宝贵时间。

【问题讨论】:

您是否可以检查两个数据库是否使用相同的 ENGINE 和 CHARSET 创建?? 是的。从我发布的 config/database.php 中可以看出,他们使用的是 ENGINE 和 CHARSET。 【参考方案1】:

所以在用不同类型的方法进行了大约 14 小时的测试后,我最终得到了我所谓的“你应该知道 hack”哈哈 ?

我在迁移表中使用第二个数据库连接名称,而不是使用数据库名称。

我在外键上使用连接名称的初始代码:

  Schema::connection('mysql2')->create('projects', function (Blueprint $table) 
      $table->id();
      $table->foreignId('user_id')->nullable()->constrained('mysql.users')->onDelete('set null');
      $table->string('name')->unique();
      $table->timestamps();

      $table->index(['id', 'user_id']);
  );

现在有效!使用数据库名称而不是外键上的连接名称:

 Schema::connection('mysql2')->create('projects', function (Blueprint $table) 
      $table->id();
      **$table->foreignId('user_id')->nullable()->constrained('db1.users')->onDelete('set null');**
      $table->string('name')->unique();
      $table->timestamps();

      $table->index(['id', 'user_id']);
  );

所以,第二个选项工作正常。 我希望这对某人也有帮助!!!

【讨论】:

以上是关于如何在 Laravel 迁移中使用多个数据库设置外键约束的主要内容,如果未能解决你的问题,请参考以下文章

使用 Laravel 迁移创建外键时出现 MySQL 错误

使用Laravel迁移创建外键时出现MySQL错误

在 Laravel 中迁移外键与雄辩的关系

Laravel 迁移 - 一般错误:1215 无法添加外键约束

迁移问题:无法在laravel中添加外键约束

如何在 LARAVEL_7 中通过迁移发送多个复选框