358

I want to combine multiple databases in my system. Most of the time the database is MySQL; but it may differ in future i.e. Admin can generate such a reports which is use source of heterogeneous database system.

So my question is does Laravel provide any Facade to deal with such situations? Or any other framework have more suitable capabilities for problem is?

miken32
  • 42,008
  • 16
  • 111
  • 154
Chintan7027
  • 7,115
  • 8
  • 36
  • 50

9 Answers9

757

From Laravel Docs: You may access each connection via the connection method on the DB facade when using multiple connections. The name passed to the connection method should correspond to one of the connections listed in your config/database.php configuration file:

$users = DB::connection('foo')->select(...);

Define Connections

Using .env >= 5.0 (or higher)

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=mysql_database
DB_USERNAME=root
DB_PASSWORD=secret

DB_CONNECTION_PGSQL=pgsql
DB_HOST_PGSQL=127.0.0.1
DB_PORT_PGSQL=5432
DB_DATABASE_PGSQL=pgsql_database
DB_USERNAME_PGSQL=root
DB_PASSWORD_PGSQL=secret

Using config/database.php

'mysql' => [
    'driver'    => env('DB_CONNECTION'),
    'host'      => env('DB_HOST'),
    'port'      => env('DB_PORT'),
    'database'  => env('DB_DATABASE'),
    'username'  => env('DB_USERNAME'),
    'password'  => env('DB_PASSWORD'),
],

'pgsql' => [
    'driver'    => env('DB_CONNECTION_PGSQL'),
    'host'      => env('DB_HOST_PGSQL'),
    'port'      => env('DB_PORT_PGSQL'),
    'database'  => env('DB_DATABASE_PGSQL'),
    'username'  => env('DB_USERNAME_PGSQL'),
    'password'  => env('DB_PASSWORD_PGSQL'),
],

Note: In pgsql, if DB_username and DB_password are the same, then you can use env('DB_USERNAME'), which is mentioned in .env first few lines.

Without .env <= 4.0 (or lower)

app/config/database.php

return array(
    'default' => 'mysql',
    'connections' => array(
        # Primary/Default database connection
        'mysql' => array(
            'driver'    => 'mysql',
            'host'      => '127.0.0.1',
            'database'  => 'mysql_database',
            'username'  => 'root',
            'password'  => 'secret'
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ),

        # Secondary database connection
       'pgsql' => [
            'driver' => 'pgsql',
            'host' => 'localhost',
            'port' => '5432',
            'database' => 'pgsql_database',
            'username' => 'root',
            'password' => 'secret',
            'charset' => 'utf8',
            'prefix' => '',
            'schema' => 'public',
        ]
    ),
);

Schema / Migration

Run the connection() method to specify which connection to use.

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

Or, at the top, define a connection.

protected $connection = 'pgsql';

Query Builder

$users = DB::connection('pgsql')->select(...);

Model

(In Laravel >= 5.0 (or higher))

Set the $connection variable in your model

class ModelName extends Model { // extend changed

    protected $connection = 'pgsql';

}

Eloquent

(In Laravel <= 4.0 (or lower))

Set the $connection variable in your model

class SomeModel extends Eloquent {
    protected $connection = 'pgsql';
}

Transaction Mode

DB::transaction(function () {
    DB::connection('mysql')->table('users')->update(['name' => 'John']);
    DB::connection('pgsql')->table('orders')->update(['status' => 'shipped']);
});

or

DB::connection('mysql')->beginTransaction();
try {
    DB::connection('mysql')->table('users')->update(['name' => 'John']);
    DB::connection('pgsql')->beginTransaction();
    DB::connection('pgsql')->table('orders')->update(['status' => 'shipped']);
    DB::connection('pgsql')->commit();
    DB::connection('mysql')->commit();
} catch (\Exception $e) {
    DB::connection('mysql')->rollBack();
    DB::connection('pgsql')->rollBack();
    throw $e;
}

You can also define the connection at runtime via the setConnection method or the on static method:

class SomeController extends BaseController {
    public function someMethod()
    {
        $someModel = new SomeModel;
        $someModel->setConnection('pgsql'); // non-static method
        $something = $someModel->find(1);
        $something = SomeModel::on('pgsql')->find(1); // static method
        return $something;
    }
}

Note: Be careful about building relationships with tables across databases! It is possible to do, but it can come with caveats depending on your database and settings.


Tested versions (Updated)

Version Tested (Yes/No)
4.2 No
5 Yes (5.5)
6 No
7 No
8 Yes (8.4)
9 Yes (9.2)

Useful Links

  1. Laravel 5 multiple database connections FROM laracasts.com
  2. Connect multiple databases in Laravel FROM tutsnare.com
  3. Multiple DB Connections in Laravel FROM fideloper.com
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
Abdulla Nilam
  • 36,589
  • 17
  • 64
  • 85
  • Hi, I tried this solution but even though there are no error messages the table is still created on the database specified in the connection "mysql" instead of "mysql2". What can I try next? :( – Pedro Araujo Jorge Jul 15 '16 at 15:57
  • 2
    You can use `class SomeModel extends Model { `and also make sure you have removed get values from env file as `env('DB_DATABASE', 'name')` when you creating new DB configuration array in database.php file as @sba has mentioned – Sadee Apr 23 '17 at 14:29
  • 1
    Hey, I'm using Lumen and for the database config part, i have only ".env" file. Not database.php. So how can I fix this? – Chanaka De Silva Jun 26 '17 at 05:17
  • 1
    @ChanakaDeSilva You just create a config folder and a database.php file in it for Lumen. Apparently Lumen is constantly checking to see if that file exists, and will use it if it does. – Ecksters Mar 26 '18 at 19:02
  • 1
    @AbdullaNilam some1 came to me to make multidb app first thought was i dont know if its possible now i know its simple ;p – binar Aug 09 '18 at 07:16
  • what if we want a primary db and then dynamic number of dbs, for e.g. separate db for each fiscal year of accounting – M.Imran Mamda Oct 21 '19 at 11:33
  • 1
    Wow .super .Thank you Sir. In my case "$users = DB::connection('mysql2')->select(...); " this is working fine Sir – Ganesan J Jun 22 '21 at 09:34
  • 1
    This answer is like an encyclopedia for multiple connection topic. – Muhammad Noman Aug 27 '21 at 06:23
  • Is there a way to relate the to databases via foreign keys ? Right now, if i define the users in another database, the migrations will not run , as it can't find the table users and hence no relation can be defined . – Berni Jun 15 '22 at 09:26
20

In Laravel 5.1, you specify the connection:

$users = DB::connection('foo')->select(...);

Default, Laravel uses the default connection. It is simple, isn't it?

Read more here: http://laravel.com/docs/5.1/database#accessing-connections

schellingerht
  • 5,726
  • 2
  • 28
  • 56
7

Laravel has inbuilt support for multiple database systems, you need to provide connection details in config/database.php file

return [
    'default' => env('DB_CONNECTION', 'mysql'),

    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix' => '',
            'strict' => false,
            'engine' => null,
        ],
'mysqlOne' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST_ONE', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE_ONE', 'forge'),
            'username' => env('DB_USERNAME_ONE', 'forge'),
            'password' => env('DB_PASSWORD_ONE', ''),
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix' => '',
            'strict' => false,
            'engine' => null,
        ],
];

Once you have this you can create two base model class for each connection and define the connection name in those models

//BaseModel.php
protected $connection = 'mysql';

//BaseModelOne.php
protected $connection = 'mysqlOne';

You can extend these models to create more models for tables in each DB.

Serg
  • 2,346
  • 3
  • 29
  • 38
Sumit Kumar
  • 1,855
  • 19
  • 19
6

Actually, DB::connection('name')->select(..) doesnt work for me, because 'name' has to be in double quotes: "name"

Still, the select query is executed on my default connection. Still trying to figure out, how to convince Laravel to work the way it is intended: change the connection.

sba
  • 404
  • 4
  • 10
  • 1
    Thank you! You saved my sanity. I tried to figure out why all my queries referred to the default database. Then I read your post and realized, that env always returned the .env values and the second parameter was just a fallback that Laravel didn't use. – Moha Oct 14 '16 at 18:00
  • Off-topic: it would be great, if admins wouldnt manipulate my posts. Or at least write me a private message what and why they want to change. I didnt figure out how to send private messags. – sba Apr 11 '18 at 08:42
  • I had a similar problem, I changed the value but not the key. It worked like this: 'database' => env('DB_NEW_DATABASE', 'myNewDatabase'). Well noted! – Fellipe Sanches May 31 '20 at 21:23
  • I hope you learned enough during these years, to understand that changing quotes helps nothing. – Your Common Sense Aug 16 '23 at 13:18
  • @YourCommonSense dont touch my posts. Or at least contact me before you want to change something. – sba Aug 24 '23 at 13:30
  • This not "your" "posts". This is a community-supported Q&A site, where you added information under Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license which allows anyone to remix, transform, and build upon this material. – Your Common Sense Aug 24 '23 at 13:46
  • You dont touch my intellectual property. This has no style. – sba Aug 25 '23 at 14:09
  • Oh, very much intellectual, `'name' has to be in double quotes: "name"` :)))))) – Your Common Sense Aug 25 '23 at 14:26
1

Using Laravel 9, and connecting to three different databases, the default one MySQL, and two other Postgres databases, I found that defining model relations works properly across models from different databases if I simply set the $connection value explicitly on all models, especially the ones that use the default database connection. This means that if you change your default connection you will have to update those models, but this happens rarely, if at all.

bhu Boue vidya
  • 379
  • 6
  • 16
0

Also you can use postgres fdw system

https://www.postgresql.org/docs/9.5/postgres-fdw.html

You will be able to connect different db in postgres. After that, in one query, you can access tables that are in different databases.

MTakumi
  • 320
  • 2
  • 10
0

This worked for me

The Middleware:

<?php 
namespace App\Http\Middleware;

use Config;
use Closure;
use DB;

class DBSelect
{

   public function handle($request, Closure $next)
   {
    //$db_name = "db1";
    $db_name = "db2";
    Config::set('database.connections.mysql.database', $db_name);

    DB::reconnect('mysql');

    return $next($request);
  }
 }

global Kernel.php

protected $middleware = [
    .....
    \App\Http\Middleware\DBSelect::class,
];

I changed some code from this answer (https://stackoverflow.com/a/64744187/4514022) and it worked for me.

Neo
  • 523
  • 7
  • 15
-1

Laravel, like many modern PHP frameworks, uses an ORM (Object-Relational Mapping) called Eloquent. Eloquent provides a comfortable and unified API for interacting with different database systems, but by default, it expects one primary connection. However, Laravel is flexible enough to manage multiple connections, even to heterogeneous databases.

Here's how you can approach the situation in Laravel:

Multiple Database Connections:

In your config/database.php file, you can define multiple database connections.

$users = DB::connection('mysql2')->select(...);
MaNsHa QaRiB
  • 37
  • 1
  • 7
-3

Not a good solution if you want to clone the existing system and to run the existing code on a new database for a new customer.

We would have to edit hundreds of eloquent calls to insert the DB::connection('foo')

iteam
  • 171
  • 1
  • 1
  • 7