核心是自动注入租户上下文并统一过滤:启动时从请求头、子域名或jwt提取租户id存入线程/协程上下文,orm或数据库层自动追加where条件,写操作校验tenant_id一致性,流程边界继承租户标识。

核心在于让每次数据操作都“自带租户身份”,不依赖开发者手动加条件,而是由框架或中间层自动拦截、识别、过滤。
租户上下文的统一注入
系统启动时,从请求头(如 Tenant-ID)、子域名(tenant1.example.com)或 JWT 载荷中提取租户标识,并存入当前线程/协程的上下文(如 Python 的 contextvars,Java 的 ThreadLocal,Node.js 的 AsyncLocalStorage)。后续所有数据库操作都可无感读取该值。
- 避免在每个 DAO 方法里重复传参或拼 SQL
- 确保异步调用链中上下文不丢失(需显式传递或使用支持异步传播的上下文机制)
- 示例:Flask 中用
@before_request解析并设置g.tenant_id
查询逻辑的自动增强
在 ORM 层或数据库访问层统一拦截 SQL 执行,对 SELECT、UPDATE、DELETE 等语句自动追加 WHERE tenant_id = ? 条件。不是靠人工写,而是靠规则注入。
- Hibernate 可用
@Filter+enableFilter动态启用租户过滤器 - MyBatis 可通过
Interceptor拦截StatementHandler,重写 SQL - 原生 SQL 场景下,建议封装一个
queryForTenant(table, conditions)工具函数,强制要求传入租户 ID
写操作的租户绑定校验
插入或更新数据前,检查待写入记录是否携带正确的 tenant_id 字段,且与当前上下文一致。防止跨租户误写。
- 在实体类或 DTO 入参校验阶段拦截非法
tenant_id值(如为空、格式错误、与上下文不匹配) - 数据库表必须为
tenant_id字段建立索引,否则自动 WHERE 过滤会拖慢性能 - 禁止允许用户直接指定
tenant_id的开放接口;该字段应由服务端生成并填充
流程边界即隔离边界
把“流程”本身作为隔离单元。例如一个审批流程实例只属于某租户,其关联的所有节点、日志、附件、历史版本,都默认继承该流程的 tenant_id,无需二次判断。
- 流程启动时绑定租户,后续所有子任务、回调、定时事件都复用该上下文
- 避免在流程内部不同服务间传递原始数据时遗漏租户信息,推荐用结构化上下文对象(如
TenantContext)透传 - 流程引擎日志、异常追踪等辅助能力也按租户分片存储,便于问题定位











