3. 数据库隔离方案:三种主流模式深度解析

多租户系统的数据库隔离,说白了就是解决一个问题:怎么让不同客户的数据安全地待在一起,又互不干扰

我做了这么多年架构,见过不少团队在这个环节翻车。有的为了省钱选了共享方案,结果客户投诉数据泄露;有的上来就搞独立数据库,运维成本直接爆炸。今天咱们就把三种方案掰开揉碎了讲清楚。

3.1 方案一:独立数据库 —— 最安全,也最贵

每个租户一个独立的数据库实例。物理隔离,数据完全分开。

核心特征:

  • 每个租户拥有独立的数据库连接
  • 备份、恢复、扩容都是独立操作
  • 安全性最高,一个租户出问题不影响其他人

我在做金融类SaaS项目时,客户明确要求必须用这个方案。为什么?合规要求。银行的数据不能跟其他企业混在一起,哪怕逻辑隔离也不行。

适用场景:

  • 金融、医疗等强监管行业
  • 大客户,愿意为安全付费
  • 租户数量少(几十到几百个)

避坑指南:

我曾经遇到一个团队,给每个租户都分配了固定连接池。结果租户一多,数据库连接数直接爆了。后来改成按需分配 + 连接池复用,才解决问题。

代码示例:动态创建数据库

-- 为每个租户创建独立数据库
CREATE DATABASE tenant_${tenantId}
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

-- 初始化表结构
USE tenant_${tenantId};
SOURCE /schema/init.sql;

3.2 方案二:共享数据库,独立Schema —— 性价比之选

同一个数据库实例,但每个租户有自己的Schema(或叫Database)。逻辑隔离,物理共享。

核心特征:

  • 共享数据库连接,减少连接开销
  • 每个Schema独立,表结构可以不同
  • 备份恢复可以按Schema操作

我个人习惯用这个方案做中型SaaS。为什么呢?你想想看,独立数据库太贵,共享表又不够安全。独立Schema刚好卡在中间,平衡了成本和隔离性。

适用场景:

  • 中型SaaS平台,租户数几百到几千
  • 租户之间数据敏感度中等
  • 需要一定的定制化能力

实现方式:

-- 创建租户Schema
CREATE SCHEMA IF NOT EXISTS tenant_${tenantId};

-- 在租户Schema下创建表
CREATE TABLE tenant_${tenantId}.orders (
  id BIGINT PRIMARY KEY,
  order_no VARCHAR(64),
  amount DECIMAL(10,2),
  created_at DATETIME
);

小技巧:我建议在应用层维护一个租户到Schema的映射表。这样切换租户时,只需要改一下数据库连接中的Schema名称,代码改动量很小。

3.3 方案三:共享数据库,共享表(行级隔离)—— 最经济,也最复杂

所有租户共用同一套表,通过tenant_id字段区分数据归属。这是最省资源的方案,但也是坑最多的方案。

核心特征:

  • 所有租户数据混在一起
  • 通过tenant_id做行级隔离
  • 资源利用率最高,运维最简单

嗯,这里要注意。行级隔离听起来简单,但实际做起来很容易出问题。我见过最典型的错误:查询时忘了加WHERE tenant_id = ?,结果A客户看到了B客户的数据。这要是出了事,客户能把你告到破产。

适用场景:

  • 小型SaaS,租户数成千上万
  • 数据敏感度低
  • 预算有限,追求极致性价比

表结构设计:

CREATE TABLE orders (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  tenant_id VARCHAR(32) NOT NULL,  -- 核心隔离字段
  order_no VARCHAR(64),
  amount DECIMAL(10,2),
  created_at DATETIME,
  INDEX idx_tenant_id (tenant_id)  -- 必须加索引
);

避坑指南:我曾经接手过一个项目,所有表都加了tenant_id,但就是没建索引。结果租户一多,全表扫描,数据库CPU直接飙到100%。记住:tenant_id必须建索引,而且最好是联合索引的第一列。

3.4 三种方案对比

维度 独立数据库 独立Schema 共享表
隔离级别 物理隔离 逻辑隔离 行级隔离
安全性 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
成本
运维复杂度
扩展性 较好 一般
适合租户数 几十 几百到几千 成千上万

3.5 我的选择建议

说实话,没有完美的方案,只有适合的方案。我一般这样选:

  1. 起步阶段:用共享表方案。快速上线,验证商业模式。
  2. 增长阶段:切换到独立Schema。成本可控,隔离性也够。
  3. 成熟阶段:大客户用独立数据库,中小客户用独立Schema。混合部署。

最后说一句:不管你选哪种方案,数据隔离的校验逻辑一定要写在数据库层,不能只靠应用层。为什么?因为应用层可能被绕过,但数据库层的约束是铁律。我习惯在每个表的查询语句里都强制带上tenant_id条件,哪怕应用层已经过滤过了。

好了,数据库隔离方案就聊到这儿。下一章咱们讲讲多租户下的缓存策略,那又是一个容易踩坑的地方。