Files
youlai-boot/docs/多租户用户管理改进说明.md
2025-12-11 08:18:01 +08:00

6.7 KiB
Raw Blame History

多租户用户管理改进说明

改进概述

本次改进实现了在用户管理中自动维护 sys_user_tenant 关联表,支持单租户和多租户两种模式的无缝切换。

核心改进

1. 用户新增时自动创建租户关联

修改文件: UserServiceImpl.saveUser()

逻辑:

  • 创建用户后,判断是否启用多租户(通过 youlai.tenant.enabled 配置)
  • 如果启用,自动向 sys_user_tenant 表插入关联记录
  • 新用户默认设置为该租户的默认租户(is_default=1
// 新增用户
boolean result = this.save(entity);

if (result) {
    // 保存用户角色
    userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
    
    // 如果启用多租户,保存用户租户关联
    if (Boolean.TRUE.equals(tenantProperties.getEnabled())) {
        saveUserTenantRelation(entity.getId(), entity.getTenantId(), true);
    }
}

2. 用户更新时同步租户关联

修改文件: UserServiceImpl.updateUser()

逻辑:

  • 比较用户的旧租户ID和新租户ID
  • 如果租户发生变更:
    • 删除旧的租户关联记录
    • 创建新的租户关联记录
// 如果启用多租户且租户发生变更,更新用户租户关联
if (Boolean.TRUE.equals(tenantProperties.getEnabled())) {
    Long newTenantId = entity.getTenantId();
    if (newTenantId != null && !newTenantId.equals(oldTenantId)) {
        // 删除旧的租户关联
        if (oldTenantId != null) {
            userTenantMapper.delete(...);
        }
        // 保存新的租户关联
        saveUserTenantRelation(userId, newTenantId, true);
    }
}

3. 用户删除时清理租户关联

修改文件: UserServiceImpl.deleteUsers()

逻辑:

  • 删除用户后,自动清理 sys_user_tenant 表中的关联记录
  • 避免产生孤立数据
boolean result = this.removeByIds(ids);

// 如果启用多租户,删除用户租户关联
if (result && Boolean.TRUE.equals(tenantProperties.getEnabled())) {
    for (Long userId : ids) {
        userTenantMapper.delete(...);
        log.info("删除用户租户关联userId={}", userId);
    }
}

4. 新增私有方法处理关联逻辑

新增方法: saveUserTenantRelation()

功能:

  • 检查关联是否已存在
  • 存在则更新 is_default 标识
  • 不存在则插入新记录
  • 添加详细日志记录

配置说明

启用多租户

application-dev.yml 中配置:

youlai:
  tenant:
    enabled: true  # 设置为 true 启用多租户
    column: tenant_id
    default-tenant-id: 1

禁用多租户

youlai:
  tenant:
    enabled: false  # 设置为 false 禁用多租户

当禁用多租户时:

  • 不会自动创建/更新/删除 sys_user_tenant 记录
  • 只使用 sys_user.tenant_id 字段
  • 零成本切换,无需修改代码

数据库设计

sys_user 表

ALTER TABLE `sys_user` 
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
ADD INDEX `idx_tenant_id` (`tenant_id`);

sys_user_tenant 表

CREATE TABLE `sys_user_tenant` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` bigint NOT NULL COMMENT '用户ID',
  `tenant_id` bigint NOT NULL COMMENT '租户ID',
  `is_default` tinyint DEFAULT '0' COMMENT '是否默认租户(1-是 0-否)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_tenant` (`user_id`, `tenant_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户租户关联表(多租户模式)';

数据初始化

执行 SQL 脚本时,会自动为现有用户创建租户关联:

INSERT INTO `sys_user_tenant` (`user_id`, `tenant_id`, `is_default`) 
SELECT `id`, 1, 1 FROM `sys_user` WHERE `is_deleted` = 0
ON DUPLICATE KEY UPDATE `is_default` = 1;

使用场景

场景1单租户模式

  • 配置:youlai.tenant.enabled = false
  • 用户只属于一个租户
  • 数据完全隔离
  • 不需要租户切换功能

场景2多租户模式

  • 配置:youlai.tenant.enabled = true
  • 用户可以属于多个租户
  • 可以在不同租户间切换
  • 通过 sys_user_tenant 表管理关联关系

关键优势

  1. 自动化管理: 创建/更新/删除用户时自动维护关联表
  2. 灵活切换: 通过配置即可在单租户和多租户模式间切换
  3. 数据一致性: 确保 sys_user.tenant_idsys_user_tenant 表数据同步
  4. 幂等操作: 支持重复执行,避免重复插入
  5. 完整日志: 每次操作都有日志记录,便于追踪问题

注意事项

  1. 事务处理: 用户的增删改操作都已添加事务注解 @Transactional
  2. 空值检查: saveUserTenantRelation() 方法会检查参数是否为空
  3. 幂等性: 插入前会检查记录是否已存在
  4. 配置优先: 所有操作都基于 tenantProperties.getEnabled() 判断

测试建议

测试场景1多租户模式下创建用户

  1. 设置 youlai.tenant.enabled = true
  2. 在租户A下创建用户"张三"
  3. 验证:
    • sys_user 表插入记录,tenant_id=A
    • sys_user_tenant 表插入记录,user_id=张三, tenant_id=A, is_default=1

测试场景2多租户模式下更新用户租户

  1. 将用户"张三"从租户A转移到租户B
  2. 验证:
    • sys_user 表更新,tenant_id=B
    • sys_user_tenant 表删除旧记录 (A),插入新记录 (B)

测试场景3多租户模式下删除用户

  1. 删除用户"张三"
  2. 验证:
    • sys_user 表标记为删除
    • sys_user_tenant 表删除关联记录

测试场景4单租户模式

  1. 设置 youlai.tenant.enabled = false
  2. 创建/更新/删除用户
  3. 验证:
    • 只操作 sys_user
    • 不操作 sys_user_tenant

修改文件清单

  • UserServiceImpl.java - 添加多租户关联维护逻辑
  • tenant_add.sql - 数据库表结构和初始化脚本
  • TenantProperties.java - 多租户配置类(已存在)
  • UserTenantMapper.java - MyBatis Mapper已存在
  • UserTenant.java - 实体类(已存在)

向后兼容性

  • 默认配置为 enabled: false,不影响现有单租户系统
  • 现有代码无需修改,只需调整配置文件即可启用多租户
  • 数据库升级脚本支持多次执行(幂等)

总结

本次改进完善了多租户用户管理机制,实现了:

  • 自动维护用户租户关联关系
  • 支持单/多租户模式灵活切换
  • 保证数据一致性和完整性
  • 提供详细的操作日志

系统现在可以零成本在单租户和多租户模式间切换,只需修改配置文件即可。