在Laravel中实现多租户架构时,灵活配置不同租户的数据库主机连接是一个常见的需求。以下是一个实现方案,允许你根据租户动态配置数据库连接。
首先,创建一个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();
});
}
创建一个中间件来识别当前请求的租户,并根据租户信息动态设置数据库连接。
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);
}
}
将中间件注册到app/Http/Kernel.php
中,确保它在处理请求时被调用。
// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
// 其他中间件
\App\Http\Middleware\IdentifyTenant::class,
],
'api' => [
// 其他中间件
\App\Http\Middleware\IdentifyTenant::class,
],
];
在应用程序中,你可以像平常一样使用Eloquent模型和查询构建器,它们会自动使用租户的数据库连接。
// 例如,获取租户的用户
$users = \App\Models\User::all();
如果你需要在同一个请求中切换租户,可以手动设置数据库连接:
// 切换到另一个租户的数据库连接
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');
在请求结束时,确保清理数据库连接,以避免内存泄漏。
// 在中间件或控制器中
DB::disconnect('tenant');
通过上述步骤,你可以实现一个灵活的多租户系统,允许每个租户使用不同的数据库主机连接。这种方法适用于需要为每个租户提供独立数据库的场景,并且可以根据租户的需求动态调整数据库连接配置。