Laravel nâng cao

Xử lý Multi-Tenancy trong Laravel: Chiến lược Database Per Tenant

Phân tích kiến trúc Multi-Tenancy cho ứng dụng SaaS. Tại sao nên chọn Database Per Tenant và cách triển khai dynamic connection trong Laravel.

newspaper

Thắng Nguyễn

8 tháng 1, 2026 schedule 3 phút đọc
Xử lý Multi-Tenancy trong Laravel: Chiến lược Database Per Tenant
Featured Image

Làm sản phẩm SaaS (Software as a Service) là ước mơ của nhiều dev. Code một lần, bán cho nhiều người thuê. Nhưng khi bắt tay vào làm, câu hỏi đầu tiên về kiến trúc luôn là: Lưu dữ liệu khách hàng như thế nào?

Có 3 chiến lược chính:

  1. Single DB, Shared Schema: Thêm cột tenant_id vào mọi bảng. (Dễ code, khó scale, rủi ro leak data cao).
  2. Single DB, Separate Schema: Chung DB nhưng khác Schema (Postgres support tốt).
  3. Database Per Tenant: Mỗi khách hàng một Database riêng biệt.

Trong bài này, tôi sẽ bảo vệ quan điểm chọn option 3 (Database Per Tenant) cho các dự án B2B nghiêm túc, và cách Laravel xử lý nó.

Tại sao chọn Database Per Tenant?

Tôi từng làm một dự án SaaS quản lý nhân sự. Ban đầu chọn cách 1 (tenant_id). Mọi thứ êm đẹp cho đến khi:

  • Một khách hàng lớn muốn backup dữ liệu của riêng họ để đem về server nội bộ -> Khóc thét vì phải đi lọc từng dòng trong DB chung.
  • Dev lỡ tay viết query quên where('tenant_id', ...) -> Thảm họa: Khách A thấy lương nhân viên khách B.

Với Database Per Tenant, dữ liệu được cô lập vật lý. Khách hàng A dùng DB db_tenant_a, Khách B dùng db_tenant_b. An toàn tuyệt đối.

Triển khai trong Laravel

Ý tưởng cốt lõi: Khi Request đến, ta xác định xem Request này của Tenant nào (qua Subdomain hoặc Header), sau đó switch database connection sang DB của Tenant đó on-the-fly.

1. Cấu hình config/database.php

Tạo một connection “động” tên là tenant.

'connections' => [
    'tenant' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'database' => null, // Sẽ điền lúc runtime
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        // ...
    ],
],

2. Middleware xác định và Switch DB

Tạo middleware IdentifyTenant.

class IdentifyTenant
{
    public function handle($request, Closure $next)
    {
        // Giả sử nhận diện qua subdomain: tenant1.app.com
        $host = $request->getHost();
        $subdomain = explode('.', $host)[0];

        // Tìm thông tin Tenant trong DB master (DB quản lý danh sách khách hàng)
        $tenant = Tenant::where('subdomain', $subdomain)->firstOrFail();

        // Switch Connection
        Config::set('database.connections.tenant.database', $tenant->database_name);
        
        // Purge cache cũ và connect lại
        DB::purge('tenant');
        DB::reconnect('tenant');

        // Set default connection cho Eloquent model dùng
        DB::setDefaultConnection('tenant');

        return $next($request);
    }
}

3. Vấn đề Migration

Như đã nói ở Quiz, chạy migration cho 1000 DB là cơn ác mộng. Tôi thường viết một Artisan command riêng: php artisan tenants:migrate.

// Command Logic
$tenants = Tenant::all();
foreach ($tenants as $tenant) {
    $this->info("Migrating for: " . $tenant->name);
    
    Artisan::call('migrate', [
        '--database' => 'tenant',
        '--path' => 'database/migrations/tenant', // Folder migration riêng cho tenant
        '--force' => true,
    ]);
    
    // Switch config lại cho vòng lặp sau (quan trọng!)
    Config::set('database.connections.tenant.database', $tenant->database_name);
    DB::purge('tenant');
}

Lưu ý quan trọng

  • Connection Management: Việc đóng mở kết nối liên tục có thể tốn resource. Cần cấu hình DB Pool hoặc dùng các dịch vụ quản lý connection ở Production.
  • Job Queues: Khi đẩy Job vào Queue, nhớ kèm theo tenant_id hoặc context để khi Worker xử lý, nó biết switch sang DB nào. Có gói spatie/laravel-multitenancy hỗ trợ việc này rất tốt.

Kết luận

Database Per Tenant phức tạp ở khâu DevOps và Migration, nhưng nó mang lại sự yên tâm tuyệt đối về bảo mật và khả năng Scale dữ liệu (Sharding) sau này. Nếu bạn xác định làm SaaS lâu dài, hãy cân nhắc mô hình này.

quizQuick Quiz
Câu 1/3

Mô hình 'Database Per Tenant' có ưu điểm gì lớn nhất?

history_edu Góc học tập & giải trí

Thử Thách Kiến Thức Lịch Sử?

Khám phá hàng trăm câu hỏi trắc nghiệm lịch sử thú vị tại HistoQuiz. Vừa học vừa chơi, nâng cao kiến thức ngay hôm nay!

Chơi Ngay arrow_forward