1. 多租户架构设计与实现原理
在SaaS系统开发中,多租户架构是基础且关键的设计模式。RuoYi-SpringBoot3-Pro采用共享数据库、独立Schema的方式实现多租户隔离,这种方案在资源利用和数据隔离之间取得了良好平衡。
1.1 核心实现机制
MyBatis-Plus的多租户插件通过SQL拦截器实现自动数据过滤。其核心类TenantLineInnerInterceptor会在SQL执行前动态修改语句,自动追加租户条件。具体工作流程如下:
- 拦截所有Mapper方法调用
- 解析当前SQL语句结构
- 根据配置判断目标表是否需要租户过滤
- 对需要过滤的表自动添加
tenant_id = ?条件 - 执行修改后的SQL语句
这种实现方式的最大优势是业务代码无需显式处理租户ID,所有过滤逻辑由框架层统一处理,显著降低了开发复杂度。
1.2 租户上下文管理
租户信息的获取通过MultiTenantHandler实现,其核心代码如下:
java复制public class MultiTenantHandler implements TenantLineHandler {
private final TenantProperties properties;
@Override
public String getTenantIdColumn() {
return properties.getColumn();
}
@Override
public boolean ignoreTable(String tableName) {
return properties.getIgnoreTables().contains(tableName);
}
@Override
public String getTenantId() {
return SecurityUtils.getTenantId();
}
}
租户ID的存储和传递采用线程本地变量(ThreadLocal)实现,确保在多线程环境下也能正确获取当前租户上下文。用户登录时,系统会将租户ID存入SecurityContext,后续操作自动继承该上下文。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 详细配置指南
2.1 基础配置参数解析
在application.yml中,多租户配置包含以下关键参数:
yaml复制tenant:
enable: true # 总开关
column: tenant_id # 租户字段名
filterTables: # 强制过滤表
ignoreTables: # 忽略过滤表
- sys_user
- sys_role
- sys_menu
ignoreLoginNames: # 超级管理员账号
- admin
各参数详细说明:
filterTables:即使表名不符合常规命名规则,也会强制进行租户过滤ignoreTables:系统级表,不参与租户隔离ignoreLoginNames:指定的管理员账号可以查看所有租户数据
2.2 数据库设计规范
为实现有效的租户隔离,数据库设计需遵循以下规范:
- 所有业务表必须包含
tenant_id字段 - 字段类型建议与主键类型一致(通常为BIGINT)
- 需要建立复合索引:(tenant_id, id)
- 系统表(用户、角色等)可不加租户字段
示例建表语句:
sql复制CREATE TABLE `biz_order` (
`id` bigint NOT NULL,
`tenant_id` bigint NOT NULL COMMENT '租户ID',
`order_no` varchar(64) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_tenant` (`tenant_id`)
) ENGINE=InnoDB;
3. 核心实现代码解析
3.1 拦截器配置
在MybatisPlusConfig中配置多租户拦截器:
java复制@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(TenantProperties tenantProperties) {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 多租户拦截器
if (Boolean.TRUE.equals(tenantProperties.getEnable())) {
interceptor.addInnerInterceptor(
new TenantLineInnerInterceptor(
new MultiTenantHandler(tenantProperties)
)
);
}
// 其他拦截器(分页、乐观锁等)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
拦截器执行顺序需要注意:
- 多租户拦截器应最先添加
- 分页拦截器
