PHP 数据库多租户架构实现方式

7次阅读

php多租户数据库架构有三种核心模式:独立数据库(最高安全、高成本)、共享数据库独立schema(平衡隔离与资源)、共享数据库共享表(轻量高效但需防漏过滤);租户识别须通过中间件统一提取并贯穿全链路。

PHP 数据库多租户架构实现方式

PHP 多租户数据库架构的核心在于隔离数据共享资源之间取得平衡,常见实现方式有三种:独立数据库、共享数据库独立 Schema、共享数据库共享表(带租户标识)。选择取决于业务规模、安全要求、运维成本和扩展性需求。

独立数据库(database-per-Tenant)

为每个租户分配一个完全独立的数据库实例(如 mysql 中的单独 database),所有表结构、数据、用户权限均物理隔离。

  • 安全性最高,天然防止跨租户数据泄露或误操作
  • 支持租户级定制化(如字段扩展、索引优化、备份策略)
  • 缺点是数据库连接数、备份、监控、迁移成本随租户数线性增长
  • laravel 中可通过动态配置 DB_DATABASE 实现,结合中间件解析租户域名或请求头,切换数据库连接

共享数据库 + 独立 Schema(Schema-per-Tenant)

所有租户共用一个数据库服务器和 database,但每个租户拥有独立的 Schema(如 postgresql 的 schema,或 MySQL 5.7+ 的 database 模拟 schema 行为)。

  • 兼顾隔离性与资源利用率,Schema 级权限可控制访问边界
  • 适合中等规模 SaaS,便于统一备份,也支持部分租户定制
  • MySQL 原生不支持真正的 schema 隔离(database ≠ schema),需通过命名规范(如 tenant_abc_users)+ 动态表前缀 + SQL 构建拦截来模拟
  • Laravel 可借助包如 stancl/tenancy 或自定义 Connection 类,在查询前自动设置当前租户的 schema 或前缀

共享数据库 + 共享表(Row-level Tenancy)

所有租户数据存于同一套表中,每张核心表增加 tenant_id 字段,并在所有查询中强制添加 WHERE tenant_id = ? 条件。

立即学习PHP免费学习笔记(深入)”;

  • 运维最轻量,水平扩展容易,适合海量租户、读写频繁但定制需求少的场景
  • 关键风险在于“租户漏过滤”——一旦查询遗漏 tenant_id 条件,将导致数据越界
  • 必须通过框架层强约束:Laravel 可用全局作用域(Global Scopes)自动注入租户条件;Doctrine 可用 Filter;原生 pdo封装查询构造器
  • 建议配合数据库行级安全策略(如 PostgreSQL Row Level Security)作为兜底防护

租户识别与上下文传递

无论采用哪种存储模式,都需稳定、安全地识别当前租户,并将 tenant_id 透传至数据访问层。

  • 常见识别方式:子域名(abc.example.com)、请求头(X-Tenant-ID)、路径前缀(/t/abc/)、JWT 声明
  • 避免在每次查询时重复解析,应由中间件统一提取并写入 Laravel 的 request()->attributes 或自定义 TenantManager 单例
  • 数据库连接、查询构建、缓存 Key、日志上下文都应绑定当前租户,形成一致的执行上下文
text=ZqhQzanResources