导读:本期聚焦于小伙伴创作的《php怎么实现多租户架构并基于数据库隔离租户数据》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《php怎么实现多租户架构并基于数据库隔离租户数据》有用,将其分享出去将是对创作者最好的鼓励。

多租户架构的核心目标是让同一个应用实例服务多个不同的租户,同时保证各租户数据的独立性与安全性。基于数据库隔离租户数据是常见的实现方式,主要分为独立数据库、共享数据库独立schema、共享数据库共享schema三种模式,其中共享数据库共享schema模式在php项目中应用最为广泛,通过给数据表添加租户标识字段实现数据隔离。

php怎么实现多租户架构并基于数据库隔离租户数据

多租户数据库隔离的核心思路

基于数据库隔离租户数据的核心逻辑分为两步,第一步是租户识别,第二步是数据过滤。租户识别通常通过请求头、域名、登录态等方式获取当前请求的租户唯一标识,数据过滤则是在所有数据库查询操作中自动拼接租户标识条件,确保查询到的数据仅属于当前租户。

租户标识获取方式

  • 域名识别:不同租户使用不同的二级域名,比如tenant1.ippipp.com、tenant2.ippipp.com,解析域名获取租户标识
  • 请求头识别:前端请求时在Header中携带租户标识字段,比如X-Tenant-Id
  • 登录态识别:用户登录后,从用户关联的租户信息中获取租户标识

数据库表结构设计

采用共享数据库共享schema模式时,所有业务表都需要添加tenant_id字段,用于标记数据所属的租户。以下是用户表的示例结构:

字段名类型说明
idint(11)用户主键
usernamevarchar(50)用户名
passwordvarchar(255)密码
tenant_idint(11)租户标识,关联租户表主键

租户表存储所有租户的基础信息,结构示例如下:

字段名类型说明
idint(11)租户主键
tenant_namevarchar(100)租户名称
domainvarchar(100)租户绑定的域名

php实现租户识别与数据隔离

租户识别中间件实现

以Laravel框架为例,我们可以创建一个中间件来识别当前请求的租户,将租户标识存储到请求上下文中,方便后续使用。

<?php

namespace AppHttpMiddleware;

use Closure;
use IlluminateHttpRequest;
use AppModelsTenant;

class IdentifyTenant
{
    public function handle(Request $request, Closure $next)
    {
        // 从请求头获取租户标识
        $tenantId = $request->header('X-Tenant-Id');
        if (!$tenantId) {
            // 从域名解析租户标识
            $host = $request->getHost();
            $tenant = Tenant::where('domain', $host)->first();
            if ($tenant) {
                $tenantId = $tenant->id;
            }
        }
        if (!$tenantId) {
            return response()->json(['code' => 401, 'msg' => '未识别到租户信息'], 401);
        }
        // 将租户标识存入请求对象
        $request->attributes->set('tenant_id', $tenantId);
        return $next($request);
    }
}

全局查询作用域实现数据过滤

为了避免在每个查询中都手动拼接tenant_id条件,我们可以创建一个全局作用域,自动为所有模型查询添加租户过滤条件。

<?php

namespace AppScopes;

use IlluminateDatabaseEloquentScope;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentBuilder;
use IlluminateHttpRequest;

class TenantScope implements Scope
{
    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function apply(Builder $builder, Model $model)
    {
        // 获取当前租户标识
        $tenantId = $this->request->get('tenant_id');
        if ($tenantId) {
            // 自动拼接tenant_id查询条件
            $builder->where('tenant_id', $tenantId);
        }
    }
}

然后在基础模型中注册这个全局作用域:

<?php

namespace AppModels;

use IlluminateDatabaseEloquentModel;
use AppScopesTenantScope;
use IlluminateSupportFacadesApp;

class BaseModel extends Model
{
    protected static function boot()
    {
        parent::boot();
        // 注册租户全局作用域
        static::addGlobalScope(new TenantScope(App::make('request')));
    }
}

数据写入时自动填充租户标识

除了查询时过滤,写入数据时也需要自动填充tenant_id字段,避免手动传入导致错误。我们可以在基础模型中重写save方法或者利用模型事件实现。

<?php

namespace AppModels;

use IlluminateDatabaseEloquentModel;
use IlluminateSupportFacadesApp;

class BaseModel extends Model
{
    protected static function boot()
    {
        parent::boot();
        // 利用creating事件自动填充tenant_id
        static::creating(function ($model) {
            $request = App::make('request');
            $tenantId = $request->get('tenant_id');
            if ($tenantId && empty($model->tenant_id)) {
                $model->tenant_id = $tenantId;
            }
        });
    }
}

注意事项

  • 对于不需要租户隔离的表,比如系统配置表、公共字典表,不需要添加tenant_id字段,也不要继承基础模型
  • 如果需要跨租户查询数据,可以在查询时使用withoutGlobalScope方法移除租户作用域
  • 租户标识的获取逻辑需要根据实际业务场景调整,比如支持子租户的场景需要额外处理租户层级关系
  • 数据库索引需要包含tenant_id字段,提升查询效率,比如用户表的索引可以设置为(tenant_id, username)
基于数据库隔离租户数据的方案兼顾了安全性与实现成本,适合大多数中小型SaaS应用,开发者可以根据项目的租户规模、数据量大小选择合适的隔离模式,核心是保证租户标识的全链路传递与数据操作的自动过滤。

php多租户架构数据库隔离tenant_id数据隔离修改时间:2026-06-17 19:12:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。