ThinkPHP 6.0多租户SaaS系统架构实战:从零构建企业级应用平台

2025-11-01 0 237

从零构建企业级多租户应用平台的完整解决方案

多租户SaaS架构概述

什么是多租户SaaS架构?

多租户SaaS(Software as a Service)架构是一种软件架构模式,允许多个客户(租户)共享同一套应用程序实例,但每个租户的数据和配置相互隔离。ThinkPHP 6.0凭借其强大的中间件、事件系统和数据库抽象层,成为构建此类系统的理想选择。

共享数据库

所有租户共享同一数据库,通过tenant_id字段隔离数据

独立数据库

每个租户拥有独立的数据库实例,数据完全隔离

混合模式

结合共享和独立数据库的优势,灵活配置

多租户数据库设计策略

基于tenant_id的数据隔离方案

在共享数据库模式下,我们通过在每个表中添加tenant_id字段来实现数据隔离。ThinkPHP的全局查询范围功能可以自动为每个查询添加租户过滤条件。

数据库迁移文件示例


<?php
// 创建租户表
class CreateTenantsTable extends Migration
{
    public function up()
    {
        Schema::create('tenants', function (Blueprint $table) {
            $table->id();
            $table->string('name', 100)->comment('租户名称');
            $table->string('domain', 255)->unique()->comment('租户域名');
            $table->string('database_name', 100)->nullable()->comment('独立数据库名');
            $table->json('config')->nullable()->comment('租户配置');
            $table->tinyInteger('status')->default(1)->comment('状态');
            $table->timestamps();
        });
    }
}

// 用户表(包含tenant_id)
class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('tenant_id')->index()->comment('租户ID');
            $table->string('name', 50)->comment('用户名');
            $table->string('email', 100)->comment('邮箱');
            $table->string('password', 255)->comment('密码');
            $table->timestamps();
            
            // 租户内唯一约束
            $table->unique(['tenant_id', 'email']);
        });
    }
}
?>
                    

租户识别中间件开发

基于域名的租户自动识别

通过自定义中间件,我们可以根据访问的域名自动识别当前租户,并设置全局的租户上下文。

租户识别中间件


<?php
namespace appmiddleware;

class TenantMiddleware
{
    public function handle($request, Closure $next)
    {
        // 获取当前访问域名
        $domain = $request->host();
        
        // 从域名中提取子域名或直接匹配
        $subdomain = $this->extractSubdomain($domain);
        
        // 查询租户信息
        $tenant = appmodelTenant::where('domain', $domain)
                    ->where('status', 1)
                    ->find();
        
        if (!$tenant) {
            // 租户不存在,返回错误页面
            return json(['error' => 'Tenant not found'], 404);
        }
        
        // 设置全局租户上下文
        appcommonTenantContext::setTenant($tenant);
        
        // 如果是独立数据库模式,切换数据库连接
        if ($tenant->database_name) {
            $this->switchDatabase($tenant->database_name);
        }
        
        return $next($request);
    }
    
    protected function extractSubdomain($domain)
    {
        $mainDomain = config('tenant.main_domain');
        return str_replace('.' . $mainDomain, '', $domain);
    }
    
    protected function switchDatabase($databaseName)
    {
        // 动态切换数据库配置
        config('database.connections.tenant.database', $databaseName);
        thinkfacadeDb::connect('tenant');
    }
}
?>
                    

全局查询范围自动过滤

// 在模型中使用全局范围自动添加tenant_id条件
class User extends Model
{
    protected $globalScope = ['tenant'];
    
    public function scopeTenant($query)
    {
        $tenantId = TenantContext::getTenantId();
        if ($tenantId) {
            $query->where('tenant_id', $tenantId);
        }
    }
}
                    

实战案例:多租户CRM系统

客户关系管理系统架构

系统功能模块

  • 客户管理(每个租户独立)
  • 销售机会跟踪
  • 合同管理
  • 数据分析报表
  • 团队协作

技术特性

  • 自动租户识别
  • 数据隔离保障
  • 可配置的业务规则
  • 多级权限控制
  • API接口支持

控制器示例:客户管理


<?php
namespace apptenantcontroller;

use appBaseController;
use apptenantmodelCustomer;

class CustomerController extends BaseController
{
    public function index()
    {
        $page = $this->request->param('page', 1);
        $limit = $this->request->param('limit', 15);
        
        // 自动过滤当前租户的客户数据
        $customers = Customer::with(['contacts', 'opportunities'])
                    ->where('status', 1)
                    ->order('create_time', 'desc')
                    ->paginate([
                        'list_rows' => $limit,
                        'page' => $page
                    ]);
        
        return json([
            'code' => 200,
            'data' => $customers,
            'msg' => 'success'
        ]);
    }
    
    public function create()
    {
        $data = $this->request->post();
        
        // 自动设置当前租户ID
        $data['tenant_id'] = appcommonTenantContext::getTenantId();
        
        $customer = new Customer();
        if ($customer->save($data)) {
            // 记录操作日志(自动关联租户)
            appcommonOperationLog::record('创建客户', $customer);
            
            return json([
                'code' => 200,
                'msg' => '客户创建成功'
            ]);
        }
        
        return json([
            'code' => 500,
            'msg' => '客户创建失败'
        ]);
    }
}
?>
                    

部署与性能优化

数据库优化策略

  • 为tenant_id字段创建索引
  • 使用数据库连接池
  • 读写分离配置
  • 定期数据归档

缓存优化方案

  • 租户配置信息缓存
  • Redis多数据库支持
  • API响应缓存
  • 静态资源CDN加速

环境配置建议

// config/tenant.php
return [
    'main_domain' => env('TENANT_MAIN_DOMAIN', 'saas.com'),
    'mode' => env('TENANT_MODE', 'shared'), // shared, isolated, hybrid
    'cache_ttl' => 3600,
    'max_tenants_per_server' => 1000,
    'auto_create_db' => false,
];
                        

ThinkPHP 6.0多租户SaaS系统架构实战:从零构建企业级应用平台
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 thinkphp ThinkPHP 6.0多租户SaaS系统架构实战:从零构建企业级应用平台 https://www.taomawang.com/server/thinkphp/1359.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务