插件窝 干货文章 Laravel多租户:如何灵活配置不同租户的数据库主机连接?

Laravel多租户:如何灵活配置不同租户的数据库主机连接?

租户 Tenant 连接 数据库 494    来源:    2025-03-11

在Laravel中实现多租户架构时,灵活配置不同租户的数据库主机连接是一个常见的需求。以下是一个实现方案,允许你根据租户动态配置数据库连接。

1. 创建租户模型和迁移

首先,创建一个Tenant模型和对应的迁移文件,用于存储租户的信息,包括数据库连接信息。

php artisan make:model Tenant -m

在迁移文件中,添加必要的字段:

// database/migrations/xxxx_xx_xx_create_tenants_table.php

public function up()
{
    Schema::create('tenants', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('domain');
        $table->string('db_host');
        $table->string('db_name');
        $table->string('db_username');
        $table->string('db_password');
        $table->timestamps();
    });
}

2. 创建中间件识别租户

创建一个中间件来识别当前请求的租户,并根据租户信息动态设置数据库连接。

php artisan make:middleware IdentifyTenant

在中间件中,根据请求的域名或其他标识符来识别租户,并设置数据库连接:

// app/Http/Middleware/IdentifyTenant.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Config;
use App\Models\Tenant;

class IdentifyTenant
{
    public function handle($request, Closure $next)
    {
        // 根据域名或其他标识符获取租户信息
        $domain = $request->getHost();
        $tenant = Tenant::where('domain', $domain)->first();

        if ($tenant) {
            // 动态设置数据库连接
            Config::set('database.connections.tenant', [
                'driver' => 'mysql',
                'host' => $tenant->db_host,
                'database' => $tenant->db_name,
                'username' => $tenant->db_username,
                'password' => $tenant->db_password,
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ]);

            // 设置默认数据库连接为租户的连接
            Config::set('database.default', 'tenant');
        }

        return $next($request);
    }
}

3. 注册中间件

将中间件注册到app/Http/Kernel.php中,确保它在处理请求时被调用。

// app/Http/Kernel.php

protected $middlewareGroups = [
    'web' => [
        // 其他中间件
        \App\Http\Middleware\IdentifyTenant::class,
    ],

    'api' => [
        // 其他中间件
        \App\Http\Middleware\IdentifyTenant::class,
    ],
];

4. 使用租户连接

在应用程序中,你可以像平常一样使用Eloquent模型和查询构建器,它们会自动使用租户的数据库连接。

// 例如,获取租户的用户
$users = \App\Models\User::all();

5. 处理租户切换

如果你需要在同一个请求中切换租户,可以手动设置数据库连接:

// 切换到另一个租户的数据库连接
Config::set('database.connections.tenant.host', $newTenant->db_host);
Config::set('database.connections.tenant.database', $newTenant->db_name);
Config::set('database.connections.tenant.username', $newTenant->db_username);
Config::set('database.connections.tenant.password', $newTenant->db_password);

// 重新连接数据库
DB::purge('tenant');
DB::reconnect('tenant');

6. 清理连接

在请求结束时,确保清理数据库连接,以避免内存泄漏。

// 在中间件或控制器中
DB::disconnect('tenant');

总结

通过上述步骤,你可以实现一个灵活的多租户系统,允许每个租户使用不同的数据库主机连接。这种方法适用于需要为每个租户提供独立数据库的场景,并且可以根据租户的需求动态调整数据库连接配置。