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

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

租户 数据库 连接 tenant 586    来源:    2025-03-14

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

1. 使用中间件识别租户

首先,你需要通过中间件来识别当前请求的租户。你可以通过域名、子域名、请求头或其他方式来确定租户。

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Config;

class IdentifyTenant
{
    public function handle($request, Closure $next)
    {
        // 假设通过子域名识别租户
        $tenantIdentifier = explode('.', $request->getHost())[0];

        // 根据租户标识符获取租户配置
        $tenantConfig = $this->getTenantConfig($tenantIdentifier);

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

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

        return $next($request);
    }

    protected function getTenantConfig($tenantIdentifier)
    {
        // 这里可以从数据库或配置文件中获取租户的数据库配置
        // 例如:
        return [
            'db_host' => 'tenant1.db.host',
            'db_port' => '3306',
            'db_name' => 'tenant1_db',
            'db_user' => 'tenant1_user',
            'db_password' => 'tenant1_password',
        ];
    }
}

2. 注册中间件

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

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

3. 使用租户连接

在中间件中,我们已经将默认的数据库连接设置为租户的连接。因此,在后续的代码中,所有的数据库操作都会使用租户的数据库连接。

// 例如,在控制器中使用租户的数据库连接
$users = DB::table('users')->get();

4. 处理租户切换

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

Config::set('database.connections.tenant.host', 'new_tenant_host');
Config::set('database.connections.tenant.database', 'new_tenant_db');
DB::purge('tenant');
DB::reconnect('tenant');

5. 缓存租户配置

为了提高性能,你可以将租户的数据库配置缓存起来,避免每次请求都去查询数据库或配置文件。

$tenantConfig = Cache::remember("tenant_config_{$tenantIdentifier}", 3600, function () use ($tenantIdentifier) {
    return $this->getTenantConfig($tenantIdentifier);
});

6. 处理异常情况

在实际应用中,可能会遇到租户配置不存在或数据库连接失败的情况。你需要在中间件中处理这些异常,并返回适当的错误响应。

try {
    // 尝试连接数据库
    DB::connection('tenant')->getPdo();
} catch (\Exception $e) {
    // 处理数据库连接失败的情况
    return response('Database connection failed', 500);
}

总结

通过上述步骤,你可以在Laravel中实现灵活的多租户数据库连接配置。这种方法允许你根据租户动态设置数据库连接,并且可以根据需要扩展和优化。