Help us understand the problem. What is going on with this article?

[Laravel5.1]複数のDBに接続させる

More than 1 year has passed since last update.

はじめに

Laravelでプロジェクト作ってるとDBを複数に分けたい場合があると思います。
ありますよね?

調べてみたら結構簡単にできたので備忘録的な扱いとして手順を残しておきます。

環境

001.png
簡単に言うとこんな感じです。
今回はすべてMySQLで構築しましたが、もちろん他のORDBと共存させることも可能みたいです。
本当はSQLServerと共存させたかったのですが、ドライバがないって怒られました。

configファイルにsqlsrvの文字があるのに標準でドライバがないってどういうことなのHomesteadさん...。
ドライバ入れたらいけるっぽいけど、工数取られそうだったので今回はオミット。
何か情報をお持ちの方がいればご教示ください:innocent:

変更手順

次の場所を変更していきます。

  • /config/database.php
  • /.env(オプション)

設定をベタ打ちする場合

/config/database.php
    'connections' => [
        // Homestead標準のデータベース
        '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,
        ],
        // Homestead上に作った他のデータベース
        'mysql_2' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', 'localhost'),
            'database'  => 'DB2',                        // データベース名のみ変更
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        // 別サーバー上のデータベース
        'mysql_3' => [
            'driver'    => 'mysql',
            'host'      => '192.168.10.15',              // Server2のIPアドレス
            'database'  => 'DB3',                        // Server2のデータベース
            'username'  => 'user2',                      // Server2のMySQLユーザー名
            'password'  => 'password2',                  // Server2のMySQLパスワード
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        ...

このように、下にどんどん接続先を足していきます。
基本的に接続先の変更がないのであれば、わざわざ/.envファイルに書き足す必要もないかなぁとは思います。
一応/.envファイルに追記していくやり方も掲載しときます。

設定ファイルから拾う場合

/config/database.php
    'connections' => [
        // Homestead標準のデータベース
        'mysql' => [ 
            'driver'    => 'mysql',
            'host'      => env('DB_HOST_1', 'localhost'),
            'database'  => env('DB_DATABASE_1', 'forge'),
            'username'  => env('DB_USERNAME_1', 'forge'),
            'password'  => env('DB_PASSWORD_1', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        // Homestead上に作った他のデータベース
        'mysql_2' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST_1', 'localhost'),
            'database'  => env('DB_DATABASE_2', 'forge'),
            'username'  => env('DB_USERNAME_1', 'forge'),
            'password'  => env('DB_PASSWORD_1', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        // 別サーバー上のデータベース
        'mysql_3' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST_3', 'localhost'),
            'database'  => env('DB_DATABASE_3', 'forge'), 
            'username'  => env('DB_USERNAME_3', 'forge'),
            'password'  => env('DB_PASSWORD_3', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],
        ...
/.env
DB_CONNECTION=mysql
DB_HOST_1=127.0.0.1
DB_DATABASE_1=DB1
DB_DATABASE_2=DB2
DB_USERNAME_1=user1
DB_PASSWORD_1=password1

DB_CONNECTION=mysql
DB_HOST_3=192.168.10.15
DB_DATABASE_3=DB3
DB_USERNAME_3=user2
DB_PASSWORD_3=password2

こんな感じですね。こっちのほうは試してないですが。

接続テスト

試しにこんな感じでテストしてみます。

/app/Http/routes.php
Route::get('/dbtest/query', function(){
    // connection先を明示しなかった場合、デフォルト接続先のDB1を見に行く
    $rows = DB::select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

    // 当然、明示した接続も可能
    $rows = DB::connection('mysql_1')->select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

    // connection先を明示してDB2を見に行く
    $rows = DB::connection('mysql_2')->select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

    // connection先を明示してDB3を見に行く
    $rows = DB::connection('mysql_3')->select('SELECT * FROM テーブル名 LIMIT 1;');
    var_dump($rows);

});

次に、モデルを定義して接続先を意識せずにDBを見に行きたいと思います。

console
php artisan make:model db2_table_sample
/app/db2_table_sample.php
namespace App;

use Illuminate\Database\Eloquent\Model;

class db2_table_sample extends Model
{
    protected $connection = 'mysql_2';
}
/app/Http/routes.php
Route::get('/dbtest/model', function(){
    // 特に接続先を明示しないでDB接続が可能
    $rows = \App\db2_table_sample::first();
    var_dump($rows);
});

ここまでできるんだったら外部DBへのリレーションとかも簡単に行きそうですね。
これは…すごいぞ…:innocent:

別DBのテーブルをマイグレーションする

こういうことをするかどうかは別として、できるかどうかの確認がしたかったので。
基本的には同一サーバー上ならともかく、別サーバーのDBをいじくり回すことはなさそうな気もします。

マイグレーションファイル作成

console
php artisan make:migration create_db3_tests
/database/migrations/yyyy_mm_dd_His_create_db3_tests.php
<?php

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

class Sample extends Migration
{

    /**
     * Run the migrations.
     * @return void
     */
    public function up() {
        Schema::connection('mysql_3')->create('db3_tests', function(Blueprint $table){
            $table->increments('id');
            $table->string('test_text');
        });
    }

    /**
     * Reverse the migrations.
     * @return void
     */
    public function down() {
        Schema::connection('mysql_3')->drop('db3_tests');
    }

}

Schema::connection('[connection名]')がポイントですね。
あとは普通のマイグレーションと全く変わりません。

マイグレーション実行

console
php artisan migrate --database=mysql_3

こちらは--database=[connection名]がポイント。
ちなみにここで、

[Illuminate\Database\QueryException]
  SQLSTATE[42000]: Syntax error or access violation: 1142 CREATE command denied to user 'user2'@'192.168.10.15' ...

的なエラーが出たら別サーバー側でそのユーザーが権限持ってないだけです。
一応その手順も。

console.192.168.10.15
mysql -u root -p

/* ユーザーリストを取得する */
select Host, User from mysql.user;
/*
+-----------+-------+
| Host      | User  |
+-----------+-------+
| 127.0.0.1 | root  |
| %         | user2 |
+-----------+-------+
*/

/* user2にすべての権限を与える */
grant all on *.* to user2;

/* user2の権限を確認する */
show grants for 'user2'@'%'\G
/*
*************************** 1. row ***************************
Grants for user2@%: GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' IDENTIFIED BY PASSWORD '...'
*/

ホントはセキュリティ上、上記のコマンド叩くとガバガバになっちゃうのでまずいんですが。

所感

正直、別サーバーのDBに対してマイグレーションできるとまでは思っていませんでした。
いともたやすくリレーションできちゃうから、かなり幅が広がった感あります。
すでに作成したプロジェクトのDBを利用して色々やったり、あるいはマスタデータは別サーバーで管理してそのデータを見に行くとか、色々できそうですね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away