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 我的选择建议
说实话,没有完美的方案,只有适合的方案。我一般这样选:
- 起步阶段:用共享表方案。快速上线,验证商业模式。
- 增长阶段:切换到独立Schema。成本可控,隔离性也够。
- 成熟阶段:大客户用独立数据库,中小客户用独立Schema。混合部署。
最后说一句:不管你选哪种方案,数据隔离的校验逻辑一定要写在数据库层,不能只靠应用层。为什么?因为应用层可能被绕过,但数据库层的约束是铁律。我习惯在每个表的查询语句里都强制带上tenant_id条件,哪怕应用层已经过滤过了。
好了,数据库隔离方案就聊到这儿。下一章咱们讲讲多租户下的缓存策略,那又是一个容易踩坑的地方。