系统多租户使用

flowchart LR
    Start[用户登录] --> QueryUser[查询sys_user表]
    QueryUser --> CheckUser{验证用户信息}
    CheckUser -->|验证失败| Failed[登录失败]
    CheckUser -->|验证成功| CheckTenant{用户是否属于多个租户}
    CheckTenant -->|否,单个租户| GetTenantId[获取用户所属租户ID]
    CheckTenant -->|是,多个租户| SelectTenant[选择默认租户 sys_user.tenant_id]
    GetTenantId --> LoginSuccess[登录成功]
    SelectTenant --> LoginSuccess
    LoginSuccess --> CheckOperation[用户启动操作]
    CheckOperation --> DataFilter[数据库操作]
    DataFilter --> AutoFilter[自动添加租户ID过滤条件]
    AutoFilter --> OpType{操作类型}
    OpType --> Query[查询操作]
    OpType --> Add[新增操作]
    OpType --> Modify[修改操作]
    OpType --> Delete[删除操作]

租户操作

flowchart LR
    A[Admin登录] --> B[默认租户1]
    B --> C[租户管理]
    C --> D[创建租户B]
    D --> E[租户B【用户】</br> 邀请admin </br>(同时属于 1、B两个租户)]
    E --> F[切换租户B<br/>右上角个人中心]
    F --> G[初始化租户B</br>组织架构]
    G --> H[配置部门 <br/> 数据自动关联租户B]
    G -.切换回租户1.-> B
    G --> I[配置角色 <br/>数据自动关联租户B]
    G --> J[配置人员<br/>数据自动关联租户B]

新增租户

通过系统管理 > 租户管理功能可以新增租户。新增租户后,需要维护租户人员信息,并进行强刷操作切换到目标租户。

操作流程

新增租户后需要完成人员配置和系统强刷,才能正常使用新租户功能。

  1. 新增租户:在租户管理页面点击"新增"按钮,填写租户基本信息
  2. 维护租户人员:为新增的租户配置管理员和相关用户
  3. 强刷系统:重新加载租户配置信息
  4. 切换租户:在前端界面切换到目标租户进行操作
租户管理界面

使用方法

多租户实现方式

多个租户共享同一个数据库(Database)和模式(Schema 通过表中的 TenantID 字段区分不同租户的数据 系统会自动维护租户 ID,开发时无需手动处理

数据表配置

在需要支持多租户的表中添加 tenant_id 字段:

表结构示例

租户隔离配置

有两种配置方式:

在实体类上添加注解:

@TenantTable

高级用法

手动切换租户

禁止直接设置

禁止在实体对象中直接设置 tenant 字段,这会导致错误。正确的切换方式是使用 TenantContextHolder。

// 手动设置租户ID(在查询前调用)
TenantContextHolder.setTenantId(1); // 切换到租户ID为1的数据

// 执行查询操作,此时强制查询到租户ID为1的用户数据
List<User> users = baseMapper.selectList(null);

跳过租户过滤

在需要查询所有租户数据时:

// 跳过租户过滤,查询所有租户的数据
TenantContextHolder.setTenantSkip();

// 执行查询操作,此时会查询所有租户的用户数据
List<User> allUsers = baseMapper.selectList(null);

示例:

跳过租户过滤示例

关闭多租户功能

在 PIGX 中,多租户是一个"按需使用"的能力,如果业务不需要租户,默认也不会影响系统运行。

系统的多租户逻辑依赖三部分:前端的租户选择、HTTP Header 中的租户标识、数据库字段 tenant_id。因此,只要关闭前端入口或数据库不包含 tenant 字段,就不会触发多租户隔离行为。

前端关闭(推荐)

推荐方式

适用于:业务只有一个租户,但未来可能会扩展,保留扩展空间。

当前端不展示"租户管理""租户切换"等菜单时:

  • 用户不会主动切换租户
  • 前端不会传递 TENANT_ID
  • 服务端自动使用默认租户(一般为租户 ID 1)

前端屏蔽方式

  • 在权限管理菜单中隐藏租户管理页面
  • 在系统顶部导航中隐藏租户切换入口
  • 删除或隐藏相关按钮即可,无需改动服务端代码

技术实现原理

系统基于 MyBatis-Plus 的多租户 SQL 解析器实现,主要包含:

租户 ID 传递

通过全局过滤器获取并存储租户 ID:

public class TenantContextHolderFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
        // 从请求头获取租户ID
        String tenantId = request.getHeader(CommonConstants.TENANT_ID);

        // 设置租户上下文
        if (StrUtil.isNotBlank(tenantId)) {
            TenantContextHolder.setTenantId(Integer.parseInt(tenantId));
        } else {
            TenantContextHolder.setTenantId(CommonConstants.TENANT_ID_1);
        }

        filterChain.doFilter(request, response);
        TenantContextHolder.clear();
    }
}

跨线程租户信息传递

使用阿里巴巴的 TransmittableThreadLocal 实现:

public class TenantContextHolder {
    private final ThreadLocal<Integer> THREAD_LOCAL_TENANT = new TransmittableThreadLocal<>();
}