6.7 KiB
6.7 KiB
多租户用户管理改进说明
改进概述
本次改进实现了在用户管理中自动维护 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表管理关联关系
关键优势
- 自动化管理: 创建/更新/删除用户时自动维护关联表
- 灵活切换: 通过配置即可在单租户和多租户模式间切换
- 数据一致性: 确保
sys_user.tenant_id和sys_user_tenant表数据同步 - 幂等操作: 支持重复执行,避免重复插入
- 完整日志: 每次操作都有日志记录,便于追踪问题
注意事项
- 事务处理: 用户的增删改操作都已添加事务注解
@Transactional - 空值检查:
saveUserTenantRelation()方法会检查参数是否为空 - 幂等性: 插入前会检查记录是否已存在
- 配置优先: 所有操作都基于
tenantProperties.getEnabled()判断
测试建议
测试场景1:多租户模式下创建用户
- 设置
youlai.tenant.enabled = true - 在租户A下创建用户"张三"
- 验证:
sys_user表插入记录,tenant_id=Asys_user_tenant表插入记录,user_id=张三, tenant_id=A, is_default=1
测试场景2:多租户模式下更新用户租户
- 将用户"张三"从租户A转移到租户B
- 验证:
sys_user表更新,tenant_id=Bsys_user_tenant表删除旧记录 (A),插入新记录 (B)
测试场景3:多租户模式下删除用户
- 删除用户"张三"
- 验证:
sys_user表标记为删除sys_user_tenant表删除关联记录
测试场景4:单租户模式
- 设置
youlai.tenant.enabled = false - 创建/更新/删除用户
- 验证:
- 只操作
sys_user表 - 不操作
sys_user_tenant表
- 只操作
修改文件清单
- ✅
UserServiceImpl.java- 添加多租户关联维护逻辑 - ✅
tenant_add.sql- 数据库表结构和初始化脚本 - ✅
TenantProperties.java- 多租户配置类(已存在) - ✅
UserTenantMapper.java- MyBatis Mapper(已存在) - ✅
UserTenant.java- 实体类(已存在)
向后兼容性
- ✅ 默认配置为
enabled: false,不影响现有单租户系统 - ✅ 现有代码无需修改,只需调整配置文件即可启用多租户
- ✅ 数据库升级脚本支持多次执行(幂等)
总结
本次改进完善了多租户用户管理机制,实现了:
- 自动维护用户租户关联关系
- 支持单/多租户模式灵活切换
- 保证数据一致性和完整性
- 提供详细的操作日志
系统现在可以零成本在单租户和多租户模式间切换,只需修改配置文件即可。