955 字
5 分钟
多租户架构在 Jeecg Boot 里的落地:行级隔离、权限体系与一次想当然的返工

五月份给人才画像系统做多租户改造,前前后后踩了不少坑,整理一下。

背景:为什么必须做多租户#

系统要同时服务多个业务方,每个业务方都有独立的人才数据,互相看不见。最朴素的做法是按业务线单独部署一套——但运维成本随业务方数量线性上涨,数据也彻底割裂,后面做汇总分析根本没得做。所以决定:一套系统,多租户共用,数据隔离。

三种隔离方案怎么选#

当时摆在桌面上的是三种经典方案:

  1. 独立数据库:隔离最彻底,但成本最高,连接管理也麻烦
  2. 共享数据库、独立 Schema:中等隔离,Oracle 下 Schema 隔离可行,但改造成本高
  3. 共享数据库、共享表、行级隔离:所有租户数据在一张表里,靠租户标识字段区分

选型时主要考虑:业务方数量可控(不是互联网 C 端场景)、要保留跨租户汇总的可能、改造成本要低。最终选了方案三,共享表 + 行级隔离,租户标识 tenant_id 落到每张业务表上。

落地:MyBatis-Plus 租户插件#

后端是 Spring Boot + Jeecg Boot + MyBatis-Plus,租户过滤直接用现成的 TenantLineInnerInterceptor,核心配置就一段:

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();
tenantInterceptor.setTenantLineHandler(new TenantLineHandler() {
@Override
public Expression getTenantId() {
return new LongValue(TenantContext.getTenantId());
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean ignoreTable(String tableName) {
// 字典、配置这类全局表不参与租户过滤
return GLOBAL_TABLES.contains(tableName);
}
});
interceptor.addInnerInterceptor(tenantInterceptor);
return interceptor;
}

要点有两个:忽略表清单必须维护好(字典表、系统配置表不能加租户条件,否则所有租户都读不到基础数据);租户上下文要跟着请求生命周期走,用 Filter 从 JWT 里解析出租户 ID,塞进 ThreadLocal,请求结束记得清理——漏了清理,线程池复用会串租户,这是多租户最阴险的坑。

踩坑:一次想当然的返工#

上线后某天,业务方反馈:列表页偶发变慢,慢的时候要两秒多。

查日志发现是租户量大之后,tenant_id 没走索引。表当初建的时候只给主键建了索引,tenant_id 是后来改造加的字段,全表扫描命中几十万行,再 filter 就慢。修复很简单:给 (tenant_id, create_time) 建联合索引。但教训值得记下来——加租户字段的时候,就应该同步评估索引,而不是等线上慢了才想起。

另一个容易漏的是手写 SQL 和存储过程。MyBatis-Plus 的拦截器只对它的 SQL 生成生效,我们系统里有不少手写 XML 和存储过程,这些地方要手动拼 AND tenant_id = ?,靠 Code Review 人工盯,容易漏。后来加了约定:所有手写 SQL 必须带租户条件,老代码里一次性补了一遍。

权限体系:租户之上还有一层#

行级隔离解决的是”租户之间”,租户内部还有用户权限:角色、菜单权限、数据范围。Jeecg Boot 自带的权限体系够用,数据范围按部门过滤,和租户过滤是两套东西,别混在一起——租户过滤是底线,权限是业务规则,底线要拦在业务规则之前,这个顺序不能反。

小结#

  • 选方案三之前,先想清楚业务方数量级和有没有跨租户汇总需求,别一上来就独立库
  • 租户拦截器省事,但忽略表清单、手写 SQL、索引、ThreadLocal 清理,每个都是雷
  • 多租户改造成熟方案一大堆,真正花时间的永远是边界情况
多租户架构在 Jeecg Boot 里的落地:行级隔离、权限体系与一次想当然的返工
https://blog.cqfly.xyz/posts/multitenant-jeecg-boot/
作者
陈庆飞
发布于
2026-05-20
许可协议
CC BY-NC-SA 4.0