Spring-Boot-Multi-Tenant-Plan
前言某中型电商平台的报表系统曾在深夜突然崩溃,起因竟是运营误删了共享表中的某租户数据列。运维团队排查发现,因为缺乏有效租户隔离,一条误操作的ALTER TABLE语句导致全平台数据混乱。
这让我们警惕:选择多租户方案的每一步,都是安全与成本的权衡 。
今天这篇文章就跟大家一起聊聊,多租户的4种常用方案,希望对你会有所帮助。
一、字段隔离方案
低成本背后的高风险
字段隔离方案,是通过统一数据表+租户ID过滤 实现逻辑隔离。
如下图所示:

初期开发成本极低,但将数据安全的压力完全转移到了代码质量控制上。
致命缺陷检查清单 :
- 任意一次DAO层查询漏加tenant_id条件 → 数据跨租户泄露
- 索引必须将tenant_id作为最左前缀 → 性能瓶颈风险
- 全表扫描类查询(如报表统计)无法避免跨租户干扰
代码防御示范
(1)MyBatis拦截器自动注入租户ID
@Intercepts({@Signature(type = Executor.class, method = "update")})
publicclass TenantInterceptor implements Interceptor {
public Object intercept(Invocation iv) throws SQLException {
MappedStatement ms = (MappedStatement) iv.getArgs()[0];
Object param = iv.getArgs()[1];
// 实体类自动填充tenant_id
if (param instanceof BaseTenantEntity) {
Field tenantIdField = param.getClass().getDeclaredField("tenantId");
tenantIdField.setAccessible(true);
if (tenantIdField.get(param) == null) {
tenantIdField.set(param, TenantContext.get());
}
}
return iv.proceed();
}
}
(2)SQL防火墙:强制全表扫描必须声明租户范围
/* 危险操作(可能扫全表) */
SELECT * FROM orders WHERE status = 'PAID';
/* 安全写法(强制tenant_id过滤) */
SELECT * FROM orders
WHERE tenant_id = 'tenant_01'
AND status = 'PAID'
/* 必须添加LIMIT防止全量拉取 */
LIMIT 1000;
适用场景建议
- 初期快速验证的MVP产品,用户量比较少的业务系统。
- 对数据隔离要求较低的内部管理系统。
二、Schema隔离
数据库层的单元房
在同一个数据库实例中为每个租户独立Schema,实现库级别隔离 。
如下图所示:

各租户表结构相同但数据独立,像小区里的不同住户单元。
运维警告清单 :
- 百级Schema数量级后,备份与迁移成本陡增
- 跨Schema关联查询必须引入中间聚合层
- 数据库连接池需按最大租户数配置 → 连接风暴风险
动态路由代码实现
(1)Spring动态数据源配置
spring:
datasource:
dynamic:
primary: master
strict: true
datasource:
master:
url: jdbc:mysql://主库地址
tenant_001:
url: jdbc:mysql://从库地址?currentSchema=tenant_001
tenant_002:
url: jdbc:mysql://从库地址?currentSchema=tenant_002