Laravel: 在另一个数据库上运行迁移

37
在我的应用程序中,每个用户都有自己的数据库,在用户注册时创建。连接和数据库数据(数据库名称、用户名、密码)保存在默认数据库的一个表中。
try{
    DB::transaction(function() {

        $website = new Website();
        $website->user_id = Auth::get()->id;
        $website->save();

        $database_name = 'website_'.$website->id;

        DB::statement(DB::raw('CREATE DATABASE ' . $database_name));

        $websiteDatabase = new WebsiteDatabase();
        $websiteDatabase->website_id = $website->id;
        $websiteDatabase->database_name = $database_name;
        $websiteDatabase->save();

    });
} catch(\Exception $e) {
    echo $e->getMessage();
}

现在我想在新用户数据库创建后运行一些迁移。
这可行吗?

2
为您的数据库添加Laravel环境,并在这些环境中调用Artisan工具?为什么要为每个客户创建一个数据库?对于Laravel应用程序来说,这听起来像是一个不寻常的决定。 - Niels B.
我们的Web应用程序类似于http://wix.com。每个用户都可以为自己创建网站,我们希望每个网站都有自己独立的数据库。在这段代码中,我为每个用户创建了单独的数据库,并将其数据保存在默认数据库中,现在我想在这个新数据库上运行一些迁移,以创建新的数据库架构。 - Pooya Saberian
8个回答

60
在你的app/config/database.php文件中,你需要:
<?php
return array(

    'default' => 'mysql',

    'connections' => array(

        # Our primary database connection
        'mysql' => array(
            'driver'    => 'mysql',
            'host'      => 'host1',
            'database'  => 'database1',
            'username'  => 'user1',
            'password'  => 'pass1'
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ),

        # Our secondary database connection
        'mysql2' => array(
            'driver'    => 'mysql',
            'host'      => 'host2',
            'database'  => 'database2',
            'username'  => 'user2',
            'password'  => 'pass2'
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ),
    ),
);

既然您在迁移中准备好了两个数据库连接,那么您可以执行以下操作:

Schema::connection('mysql2')->create('some_table', function($table)
{
    $table->increments('id');
});

这应该可以运行。 更多信息请参见:http://fideloper.com/laravel-multiple-database-connections


1
我的配置文件中没有第二个数据库连接。数据库连接细节保存在主数据库中! - Pooya Saberian
2
我认为你应该澄清你的问题,或者展示一些代码以使其更易理解... - pietrovismara
我相信这将在默认数据库中创建迁移表,但是如果从头开始运行迁移呢?(这是我刚刚在Laravel 10上的经历)。Fernando的回答没有这个问题。 - undefined

59

如果您将数据库配置放在database.php文件中,则可以帮助您:

php artisan migrate --database=**otherDatabase**

我已经在Laravel Forge Deploy脚本中设置了两个迁移,分别为php artisan migratephp artisan migrate --database=arc_mysql - Anon30
你开玩笑的吧,用四个星号? - Toskan

16

如果您的意思是使用不同的数据库连接,文档中已经存在相应说明:

Schema::connection('foo')->create('users', function (Blueprint $table) {
    $table->bigIncrements('id');
});

6

我有同样的问题,我的解决方案是首先使用Config::set更改数据库,然后运行Artisan::call("migrate")。 根据你的代码:

DB::statement(DB::raw('CREATE DATABASE ' . $database_name));
Config::set('database.connections.mysql.database', $database_name);
Artisan::call("migrate --database=mysql");

配置仅在您的会话中更改,然后将作为当前设置重置。


2

记住每个迁移对应哪个数据库很繁琐。

对于 Laravel 5.5,我使用了以下方法:

public function up()
{

 // this line is important
  Illuminate\Support\Facades\DB::setDefaultConnection('anotherDatabaseConnection');


   Schema::table('product',
          function (Blueprint $table)
     {
        $table->string('public_id', 85)->nullable()->after('ProductID');
     });

  // this line is important, Probably you need to set this to 'mysql'
   Illuminate\Support\Facades\DB::setDefaultConnection('nameOfYourDefaultDatabaseConnection');
}

所有迁移都可以自动运行,无需手动指定数据库即可运行。

请注意,迁移表存储在默认数据库中。


当然,虽然本地人不知道它。 - Tebe

1
我曾经遇到过同样的问题,Joe的答案在我的情况下不起作用,因为我有不同的数据库连接(因此主机、端口、用户名和密码都不同)。
因此,迁移必须一直进行许多重新连接:
- 迁移从默认数据库开始(在我的情况下是client_1) - 从表migrationsclients中获取内容 - 断开默认数据库的连接 - 连接到client_2的数据库,运行迁移部分,断开client_2的连接 - 再次连接到默认数据库,存储迁移“日志”
然后为每个客户端循环。
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        $defaultConnection = BackendConfig::getDatabaseConfigArray();
        $clients = ClientController::returnDatabasesForArtisan();

        foreach ($clients as $client) {
            BackendConfig::setDatabaseFromClient($client);

            Schema::create('newtable', function (Blueprint $table) {
                $table->increments('id')->unsigned();
                $table->timestamps();
            });
            BackendConfig::setDatabaseFromArray($defaultConnection);
        }
    }

魔法存储在哪个类中:

class BackendConfig
{
    public static function getDatabaseConfigArray($client_id = 1)
    {
        $connection = config('database.default');

        return [
            'id' => $client_id,
            'host' => config("database.connections.$connection.host"),
            'port' => config("database.connections.$connection.port"),
            'username' => config("database.connections.$connection.username"),
            'password' => config("database.connections.$connection.password"),
        ];
    }

    public static function setDatabaseFromArray($array)
    {
        self::setDatabase($array['id'], $array['host'], $array['port'], $array['username'], $array['password'], true);
        DB::disconnect();
    }

    public static function setDatabaseFromClient(Client $client)
    {
        DB::disconnect();
        self::setDatabase($client->id, $client->database->host, $client->database->port, $client->database->username, $client->database->password, true);
    }

    public static function setDatabase($client_id, $host, $port, $username, $password)
    {
        $connection = config('database.default');

        $database_name = $connection . '_' . $client_id;

        config([
            "database.connections.$connection.database" => $database_name,
            "database.connections.$connection.host" => $host,
            "database.connections.$connection.port" => $port,
            "database.connections.$connection.username" => $username,
            "database.connections.$connection.password" => $password,
        ]);
}

通过这种方法,我可以在每个客户端上运行完全相同的迁移,但是迁移仅存储在client_1中,我的主客户端。
但是,请注意两个DB::disconnect();。如果没有这些,情况将会混乱,因为迁移日志将存储在另一个客户端的数据库中或类似情况。
哦,顺便说一下,ClientController没有任何特殊作用:
public static function returnDatabasesForArtisan()
{
    return Client::select('*')->with('database')->get();
}

0

我想我终于理清了这个混乱的问题…… 这个解决方案不需要为每个租户的数据库进行配置,并且只需要运行一次。

class MigrationBlah extends Migration {
  public function up() {
    $dbs = DB::connection('tenants')->table('tenants')->get();
    foreach ($dbs as $db) {
      Schema::table($db->database . '.bodegausuarios', function($table){
        $table->foreign('usuario')->references('usuarioid')->on('authusuarios');
      });
    }
  }
}

在我的database.php中有一个名为“tenants”的连接,其中包含所有租户的数据库名称。我将默认连接设置为我的租户数据库。该数据库负责处理迁移表。

使用foreach语句,它会遍历每个租户数据库并对其运行迁移。

在您的默认连接上,您应该配置一个可以访问所有租户数据库的用户才能使其正常工作。


使用这种方法,您无法为单个租户进行迁移。 - Renan Coelho

-1

最佳解决方案是您可以在AppServiceProvide上调用此方法。

这是这种类型问题的最佳解决方案。我在我的项目中使用它。在我的情况下,我有两个环境开发生产。因此,当项目处于开发模式时,它将查找本地服务器,否则查找实时服务器。因此,您可以在此处设置动态-DB概念。

您必须创建一个函数,然后在App\Providers\AppServiceProvide.phpboot()函数内调用此函数。

    public function boot()
    {
       DBConnection();

    }

我为此创建了一个名为Helper的文件。因此,我的代码在helper.php中。
 function DBConnection()
 {
  if( env('APP_ENV') ==  'local' )
   {   $databse_name = "test_me";
       $host = '127.0.0.1';
       $user="root";
      $password="";
   }
    else
  {
    $databse_name = 'tic_tac';
    $host = 'localhost';
    $user="";
    $password="";
  }
    $state = true;
   try {
      Config::set('database.connections.myConnection', array(
        'driver'    => 'mysql',
        'host'      => $host,
        'database'  => $databse_name,
        'username'  => $user,
        'password'  => $password,
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict' => false,
     ));
    /* \DB::setDefaultConnection('myConnection');
      $state = \DB::connection()->getPdo();*/

     Config::set('database.connections.myConnection.database', $databse_name);
     \DB::setDefaultConnection('myConnection');
      \DB::reconnect('myConnection');

   } catch( \Exception $e) {
      $state = false;
   }
 return $state;
}

这不仅适用于迁移,而且适用于任何地方。 - pankaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接