refactor: 租户重构

This commit is contained in:
Ray.Hao
2025-12-11 08:18:01 +08:00
parent 36d2db6dc5
commit 47cabcbcfc
14 changed files with 789 additions and 44 deletions

View File

@@ -0,0 +1,228 @@
# 多租户用户管理改进说明
## 改进概述
本次改进实现了在用户管理中自动维护 `sys_user_tenant` 关联表,支持单租户和多租户两种模式的无缝切换。
## 核心改进
### 1. 用户新增时自动创建租户关联
**修改文件**: `UserServiceImpl.saveUser()`
**逻辑**:
- 创建用户后,判断是否启用多租户(通过 `youlai.tenant.enabled` 配置)
- 如果启用,自动向 `sys_user_tenant` 表插入关联记录
- 新用户默认设置为该租户的默认租户(`is_default=1`
```java
// 新增用户
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
- 如果租户发生变更:
- 删除旧的租户关联记录
- 创建新的租户关联记录
```java
// 如果启用多租户且租户发生变更,更新用户租户关联
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` 表中的关联记录
- 避免产生孤立数据
```java
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` 中配置:
```yaml
youlai:
tenant:
enabled: true # 设置为 true 启用多租户
column: tenant_id
default-tenant-id: 1
```
### 禁用多租户
```yaml
youlai:
tenant:
enabled: false # 设置为 false 禁用多租户
```
当禁用多租户时:
- ✅ 不会自动创建/更新/删除 `sys_user_tenant` 记录
- ✅ 只使用 `sys_user.tenant_id` 字段
- ✅ 零成本切换,无需修改代码
## 数据库设计
### sys_user 表
```sql
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 表
```sql
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 脚本时,会自动为现有用户创建租户关联:
```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_id``sys_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`,不影响现有单租户系统
- ✅ 现有代码无需修改,只需调整配置文件即可启用多租户
- ✅ 数据库升级脚本支持多次执行(幂等)
## 总结
本次改进完善了多租户用户管理机制,实现了:
- 自动维护用户租户关联关系
- 支持单/多租户模式灵活切换
- 保证数据一致性和完整性
- 提供详细的操作日志
系统现在可以零成本在单租户和多租户模式间切换,只需修改配置文件即可。