租户隔离边界
Forge 通过 TenantLineInnerInterceptor 实现多租户数据隔离。你在开发时需要了解哪些表需要 tenant_id,以及跨租户查询的注意事项。
工作原理
TenantLineInnerInterceptor 是 MyBatis-Plus 提供的租户拦截器,它在 SQL 执行前自动追加租户条件:
sql
-- 你写的 SQL
SELECT * FROM sys_user WHERE status = '0'
-- 拦截器自动改写为
SELECT * FROM sys_user WHERE status = '0' AND tenant_id = 1拦截器对 SELECT、UPDATE、DELETE 都会自动追加 WHERE tenant_id = ?。
租户 ID 规则
| 规则 | 说明 |
|---|---|
业务数据 tenant_id | 必须设为 1(默认租户) |
禁止设为 0 | 0 的数据对所有租户不可见 |
sys_resource(菜单/权限) | 不受租户拦截,tenant_id 设为 1 |
sql
-- 正确:内置数据 tenant_id = 1
INSERT INTO sys_dict_type (dict_name, dict_type, tenant_id)
VALUES ('性别', 'sys_user_sex', 1);
-- 禁止:tenant_id = 0,数据不可见
INSERT INTO sys_dict_type (dict_name, dict_type, tenant_id)
VALUES ('性别', 'sys_user_sex', 0);需要 tenant_id 的表
| 表类型 | 需要 tenant_id | 说明 |
|---|---|---|
| 业务数据表 | 是 | 用户、订单、配置等 |
| 系统管理表 | 是 | sys_user、sys_role 等 |
| 字典表 | 是 | sys_dict_type、sys_dict_data |
| 菜单/权限表 | 是 | sys_resource(不拦截,但字段必须有) |
| Flowable 引擎表 | 否 | 框架管理,不纳入 |
| 框架运行表 | 否 | forge_schema_history 等 |
跨租户查询
如果业务需要跨租户查询(如平台管理员查看所有租户数据),需要忽略租户拦截:
java
// 方式一:指定方法忽略租户
@InterceptorIgnore(tenantLine = "true")
List<SysUserEntity> selectAllTenantUsers();xml
<!-- Mapper XML 中不需要手动写 tenant_id,拦截器会自动处理 -->
<select id="selectUserPage" resultType="SysUserVO">
SELECT u.id, u.username, u.nickname
FROM sys_user u
WHERE u.del_flag = 0
</select>注意事项
- 不要在 XML 中手动写
AND tenant_id = #{tenantId},拦截器会自动追加,否则会重复条件 - 新建表时必须包含
tenant_id字段,否则拦截器追加条件时 SQL 报错 - 如果表不需要租户隔离,在
TenantLineInnerInterceptor配置中排除该表 - 前端不需要传
tenantId,后端从上下文自动获取
