229 lines
6.7 KiB
Markdown
229 lines
6.7 KiB
Markdown
# 多租户用户管理改进说明
|
||
|
||
## 改进概述
|
||
|
||
本次改进实现了在用户管理中自动维护 `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`,不影响现有单租户系统
|
||
- ✅ 现有代码无需修改,只需调整配置文件即可启用多租户
|
||
- ✅ 数据库升级脚本支持多次执行(幂等)
|
||
|
||
## 总结
|
||
|
||
本次改进完善了多租户用户管理机制,实现了:
|
||
- 自动维护用户租户关联关系
|
||
- 支持单/多租户模式灵活切换
|
||
- 保证数据一致性和完整性
|
||
- 提供详细的操作日志
|
||
|
||
系统现在可以零成本在单租户和多租户模式间切换,只需修改配置文件即可。
|