You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spatie Laravel Multitenancy问题:误访问Landlord数据库users表

问题描述

在Laravel应用中集成Spatie Laravel Multitenancy时,运行应用出现以下错误:

Illuminate\Database\QueryException
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'laravel.users' doesn't exist
SELECT * FROM `users`

配置详情

数据库配置

已为租户(tenant)和主库(landlord)配置独立数据库,连接信息如下:

'tenant' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => null,
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],

'landlord' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    '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' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],

多租户配置(config/multitenancy.php)

<?php

use Illuminate\Broadcasting\BroadcastEvent;
use Illuminate\Events\CallQueuedListener;
use Illuminate\Mail\SendQueuedMailable;
use Illuminate\Notifications\SendQueuedNotifications;
use Spatie\Multitenancy\Actions\ForgetCurrentTenantAction;
use Spatie\Multitenancy\Actions\MakeQueueTenantAwareAction;
use Spatie\Multitenancy\Actions\MakeTenantCurrentAction;
use Spatie\Multitenancy\Actions\MigrateTenantAction;
use Spatie\Multitenancy\Models\Tenant;
use Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask;

return [
    'tenant_finder' => Spatie\Multitenancy\TenantFinder\DomainTenantFinder::class,

    'tenant_artisan_search_fields' => [
        'id',
    ],

    'switch_tenant_tasks' => [
        SwitchTenantDatabaseTask::class,
    ],

    'tenant_model' => Tenant::class,

    'queues_are_tenant_aware_by_default' => true,

    'tenant_database_connection_name' => 'tenant',

    'landlord_database_connection_name' => null,

    'current_tenant_container_key' => 'currentTenant',

    'shared_routes_cache' => false,

    'actions' => [
        'make_tenant_current_action' => MakeTenantCurrentAction::class,
        'forget_current_tenant_action' => ForgetCurrentTenantAction::class,
        'make_queue_tenant_aware_action' => MakeQueueTenantAwareAction::class,
        'migrate_tenant' => MigrateTenantAction::class,
    ],

    'queueable_to_job' => [
        SendQueuedMailable::class => 'mailable',
        SendQueuedNotifications::class => 'notification',
        CallQueuedListener::class => 'class',
        BroadcastEvent::class => 'event',
    ],

    'tenant_aware_jobs' => [
        // ...
    ],

    'not_tenant_aware_jobs' => [
        // ...
    ],
];

环境变量(.env)

DB_CONNECTION=landlord
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

错误背景

错误触发于应用访问users表时。按照多租户架构设计,每个租户应拥有独立的users表,但当前应用似乎在访问主库(landlord)的users表,而非当前租户数据库中的对应表。

预期效果

已按文档配置租户与主库的独立数据库,期望应用能根据当前租户自动切换到对应数据库,访问users表时使用租户数据库内的表。


解决方案

1. 绑定用户模型到租户数据库连接

修改User模型,指定使用租户连接:

// app/Models/User.php
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Multitenancy\Models\Concerns\UsesTenantConnection;

class User extends Authenticatable
{
    // 使用Spatie提供的trait自动关联租户连接
    use UsesTenantConnection;

    // ... 其他模型代码
}

如果不需要全局绑定,也可以手动指定连接字段:

protected $connection = 'tenant';

2. 修复多租户配置中的主库连接

在config/multitenancy.php中,将主库连接设置为landlord:

'landlord_database_connection_name' => 'landlord',

确保主库模型(如Tenant本身)能正确使用主库连接,避免连接混淆。

3. 验证租户模型的数据库字段配置

如果自定义了租户模型,确认数据库名字段的映射正确:

// app/Models/Tenant.php(自定义租户模型时)
namespace App\Models;

use Spatie\Multitenancy\Models\Tenant as SpatieTenant;

class Tenant extends SpatieTenant
{
    // 若租户表中存储数据库名的字段不是默认的`database`,重写此方法
    public function getDatabaseName(): string
    {
        return $this->tenant_db_name; // 替换为你的实际字段名
    }
}

同时确保config/multitenancy.php中的tenant_model指向正确的自定义模型。

4. 确认租户切换逻辑生效

  • 检查请求域名是否已关联到对应租户记录(DomainTenantFinder依赖域名匹配租户)
  • 在控制器/中间件中添加调试代码,验证当前租户和连接:
dd(tenant()?->id, tenant()?->database_name, DB::connection()->getName());

如果tenant()返回null,说明租户未被正确识别,需检查域名解析、租户记录是否存在。

5. 确保租户数据库已完成迁移

执行租户迁移命令,确保每个租户数据库都有users表:

php artisan tenant:migrate

若租户数据库未创建,可通过命令生成:

php artisan tenant:create {tenant-name} --domain={tenant-domain} --database={tenant-db-name}

6. 注册多租户中间件

检查app/Http/Kernel.php,确保添加了租户切换的核心中间件:

protected $middlewareGroups = [
    'web' => [
        // ... 其他中间件
        \Spatie\Multitenancy\Http\Middleware\MakeTenantCurrent::class,
        \Spatie\Multitenancy\Http\Middleware\EnsureValidTenantSession::class,
    ],

    'api' => [
        // ... 其他中间件
        \Spatie\Multitenancy\Http\Middleware\MakeTenantCurrent::class,
    ],
];

7. 清理配置缓存

修改配置后清理缓存,确保新配置生效:

php artisan config:clear
php artisan cache:clear

内容的提问来源于stack exchange,提问作者H.Hassan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:32:07