Chạy Laravel với nhiều kết nối cơ sở dữ liệu
Bài đăng này đã không được cập nhật trong 6 năm
Trong rất nhiều trường hợp dự án của chúng ta yêu cầu phải sử dụng nhiều kết nối cơ sở dử liệu trong cùng một ứng dụng, chúng ta sẽ làm việc này với ứng dụng Laravel như thế nào?
Chuẩn bị
Chúng ta sẽ sử dụng 3 database khác nhau, trong đó 2 database sử dụng MYSQL và 1 sử dụng SQL Server:
- Database
laramultidb
với connection name làmysql
sử dụng MySQL engine. - Database
laramultidb2
với connection name làmysql2
sử dụng MySQL engine. - Database
laravelmultidb
với connection name làsqlsrv
sử dụng SQL Server Engine.
Đây là file config/database.php
:
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
],
'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', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
'mysql2' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE2', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST_SQLSRV', 'localhost'),
'port' => env('DB_PORT_SQLSRV', '1433'),
'database' => env('DB_DATABASE_SQLSRV', 'forge'),
'username' => env('DB_USERNAME_SQLSRV', 'forge'),
'password' => env('DB_PASSWORD_SQLSRV', ''),
'charset' => 'utf8',
'prefix' => '',
],
],
Và file .env
:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laramultidb
DB_USERNAME=yourusername
DB_PASSWORD=secret
DB_DATABASE2=laramultidb2
DB_HOST_SQLSRV=127.0.0.1
DB_PORT_SQLSRV=1433
DB_DATABASE_SQLSRV=laravelmultidb
DB_USERNAME_SQLSRV=sa
DB_PASSWORD_SQLSRV=secret
Migration & Model
Khi muốn tạo migration cho cho database nào thì define connection name của database đó trong Schema
:
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::connection('mysql2')->create('types', function (Blueprint $table) {
$table->increments('id');
$table->string('code')->index();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::connection('mysql2')->drop('types');
}
File migration trên sẽ migrate table types
vào connection mysql2
với DB name là laravmultidb2
, nếu không define connection name, Laravel sẽ sử dụng connection mặc định.
Để chỉ định connection trong model, hãy sử dụng attribute $connection
:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Type extends Model
{
protected $connection = 'mysql2';
}
Relationship giữa các database
Yêu cầu:
Type (connection: mysql2) has many Post (connection: mysql)
Type (connection: mysql2) has many Mail (connection: sqlsrv)
Chúng ta hoàn toàn có thể làm được việc này thông qua model, chỉ định connection bằng attribute $connection
:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Type extends Model
{
protected $connection = 'mysql2';
/**
* one to many relationship with Post (mysql connection)
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function posts()
{
return $this->hasMany(Post::class, 'type_code', 'code');
}
/**
* one to many relationship with Mail (sqlsrv connection)
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function mails()
{
return $this->hasMany(Mail::class, 'type_code', 'code');
}
}
Model Post
cũng tương tự:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Mail extends Model
{
protected $connection = 'sqlsrv';
/**
* override date format since SQL server has own date format for timestamp fields
* @var string
*/
protected $dateFormat = 'Y-m-d H:i:s';
/**
* one to many inversion relationship with Type (mysql2 connection)
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function type()
{
return $this->belongsTo(Type::class, 'type_code', 'code');
}
}
Seed dummy data vào các table và sử dụng tinker để test, wow, nó đã hoạt động:
Vậy là sử dụng relationship giữa các connection khác nhau đã thành công mỹ mãn.
Join
Chúng ta sẽ chỉ định connection cho table thì mới thực hiện join được, nếu không sẽ báo lỗi:
Post::join('laramultidb2.types as db2type', 'posts.type_code', '=', 'db2type.code')->first()
Thay vì sử dụng model, chúng ta có thể sử dụng Query Builder:
Chỉ định connection cho query builder:
Chúng ta tiếp tục join table mails
(SQL Server) và table types
(MySql)
Rất tiếc, có lẽ như chúng ta ko thể join giữa các database engine khác nhau (hoặc có thể là tác giả chưa thực hiện đúng cách)
Kết
-
Chúng ta hoàn toàn có thể sử dụng nhiều kết nối cơ sở dữ liệu trên cũng 1 ứng dụng Laravel.
-
Có thể sử dụng relationship giữa các connection thông qua model
-
Có thể join giữa các table trên các connection khác nhau, nhưng có lẽ chúng phải cùng host / database engine (hoặc có thể là tác giả chưa thực hiện đúng cách)
Tham khảo: https://medium.com/teknomuslim/how-to-run-laravel-using-multiple-database-connections-d7e8dcb7ed2a
All rights reserved