```
fix(tenant): 修复私有化部署下的租户注册和引导配置逻辑 - 修改 PrivateDeploymentProperties 中的 tenantRegisterEnabled 方法, 在私有化模式下始终返回 false - 修改 PrivateDeploymentProperties 中的 tenantBootstrapEnabled 方法, 在私有化模式下始终返回 true - 在 SystemUpdateService 中注入 PrivateDeploymentProperties 依赖 - 添加 migrate_v20260527_consolidate_private_tenants 数据库迁移方法 - 实现私有化部署下合并多租户功能,保留最早租户并替换其余租户ID - 迁移涉及 t_app、t_operation_log、t_migrate_key 等表的数据 - 更新子账号的 parent_id 指向保留的租户 - 删除合并后多余的租户记录 ```
这个提交包含在:
父节点
db986808f2
当前提交
e3e16352d5
@ -23,12 +23,12 @@ public class PrivateDeploymentProperties {
|
|||||||
public String getMode() { return mode; }
|
public String getMode() { return mode; }
|
||||||
public void setMode(String mode) { this.mode = mode; }
|
public void setMode(String mode) { this.mode = mode; }
|
||||||
|
|
||||||
public boolean isTenantRegisterEnabled() { return tenantRegisterEnabled; }
|
public boolean isTenantRegisterEnabled() { return isPrivate() ? false : tenantRegisterEnabled; }
|
||||||
public void setTenantRegisterEnabled(boolean tenantRegisterEnabled) {
|
public void setTenantRegisterEnabled(boolean tenantRegisterEnabled) {
|
||||||
this.tenantRegisterEnabled = tenantRegisterEnabled;
|
this.tenantRegisterEnabled = tenantRegisterEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTenantBootstrapEnabled() { return tenantBootstrapEnabled; }
|
public boolean isTenantBootstrapEnabled() { return isPrivate() ? true : tenantBootstrapEnabled; }
|
||||||
public void setTenantBootstrapEnabled(boolean tenantBootstrapEnabled) {
|
public void setTenantBootstrapEnabled(boolean tenantBootstrapEnabled) {
|
||||||
this.tenantBootstrapEnabled = tenantBootstrapEnabled;
|
this.tenantBootstrapEnabled = tenantBootstrapEnabled;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,8 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.xuqm.tenant.config.PrivateDeploymentProperties;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -47,9 +49,11 @@ public class SystemUpdateService {
|
|||||||
private String deployRoot;
|
private String deployRoot;
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
private final PrivateDeploymentProperties deployProps;
|
||||||
|
|
||||||
public SystemUpdateService(DataSource dataSource) {
|
public SystemUpdateService(DataSource dataSource, PrivateDeploymentProperties deployProps) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
|
this.deployProps = deployProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 公开接口 ────────────────────────────────────────────────────────────────
|
// ── 公开接口 ────────────────────────────────────────────────────────────────
|
||||||
@ -409,6 +413,7 @@ public class SystemUpdateService {
|
|||||||
|
|
||||||
migrate_v20260101_drop_device_id_unique_index(emit);
|
migrate_v20260101_drop_device_id_unique_index(emit);
|
||||||
migrate_v20260527_push_license_operation_logs(emit);
|
migrate_v20260527_push_license_operation_logs(emit);
|
||||||
|
migrate_v20260527_consolidate_private_tenants(emit);
|
||||||
// 新版本迁移在此追加,例如:
|
// 新版本迁移在此追加,例如:
|
||||||
// migrate_v20260601_add_app_extra_column(emit);
|
// migrate_v20260601_add_app_extra_column(emit);
|
||||||
|
|
||||||
@ -509,6 +514,96 @@ public class SystemUpdateService {
|
|||||||
recordMigration(id, "push-service 和 license-service 新增操作日志表");
|
recordMigration(id, "push-service 和 license-service 新增操作日志表");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私有化部署下合并多租户:保留最早的租户,将其余租户的 tenant_id 全部替换,然后删除多余租户。
|
||||||
|
* 仅在 DEPLOYMENT_MODE=PRIVATE 时执行。
|
||||||
|
*/
|
||||||
|
private void migrate_v20260527_consolidate_private_tenants(Consumer<String> emit) {
|
||||||
|
if (!deployProps.isPrivate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String id = "v20260527_consolidate_private_tenants";
|
||||||
|
if (migrationApplied(id)) {
|
||||||
|
emit.accept(" [已应用] " + id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try (Connection conn = dataSource.getConnection()) {
|
||||||
|
// 1. 找到最早的租户
|
||||||
|
String keepId;
|
||||||
|
try (PreparedStatement ps = conn.prepareStatement(
|
||||||
|
"SELECT id FROM t_tenant ORDER BY created_at ASC LIMIT 1");
|
||||||
|
ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (!rs.next()) {
|
||||||
|
emit.accept(" [跳过] " + id + ": 无租户数据");
|
||||||
|
recordMigration(id, "私有化合并多租户(无数据)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
keepId = rs.getString("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 统计需要迁移的租户数
|
||||||
|
int totalTenants;
|
||||||
|
try (PreparedStatement ps = conn.prepareStatement("SELECT COUNT(*) FROM t_tenant");
|
||||||
|
ResultSet rs = ps.executeQuery()) {
|
||||||
|
rs.next();
|
||||||
|
totalTenants = rs.getInt(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalTenants <= 1) {
|
||||||
|
emit.accept(" [跳过] " + id + ": 仅 " + totalTenants + " 个租户,无需合并");
|
||||||
|
recordMigration(id, "私有化合并多租户(仅" + totalTenants + "个)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit.accept(" [合并] 保留最早租户 " + keepId + ",共 " + totalTenants + " 个租户");
|
||||||
|
|
||||||
|
// 3. 替换所有表中的 tenant_id
|
||||||
|
String[][] tables = {
|
||||||
|
{"t_app", "tenant_id"},
|
||||||
|
{"t_operation_log", "tenant_id"},
|
||||||
|
{"t_migrate_key", "tenant_id"},
|
||||||
|
};
|
||||||
|
int totalUpdated = 0;
|
||||||
|
for (String[] tbl : tables) {
|
||||||
|
try (PreparedStatement ps = conn.prepareStatement(
|
||||||
|
"UPDATE " + tbl[0] + " SET " + tbl[1] + " = ? WHERE " + tbl[1] + " != ?")) {
|
||||||
|
ps.setString(1, keepId);
|
||||||
|
ps.setString(2, keepId);
|
||||||
|
int rows = ps.executeUpdate();
|
||||||
|
if (rows > 0) {
|
||||||
|
emit.accept(" " + tbl[0] + ": 更新 " + rows + " 行");
|
||||||
|
totalUpdated += rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 子账号的 parent_id 指向保留的租户
|
||||||
|
try (PreparedStatement ps = conn.prepareStatement(
|
||||||
|
"UPDATE t_tenant SET parent_id = ? WHERE parent_id IS NOT NULL AND parent_id != ?")) {
|
||||||
|
ps.setString(1, keepId);
|
||||||
|
ps.setString(2, keepId);
|
||||||
|
int rows = ps.executeUpdate();
|
||||||
|
if (rows > 0) {
|
||||||
|
emit.accept(" t_tenant.parent_id: 更新 " + rows + " 个子账号");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 删除多余租户
|
||||||
|
try (PreparedStatement ps = conn.prepareStatement(
|
||||||
|
"DELETE FROM t_tenant WHERE id != ?")) {
|
||||||
|
ps.setString(1, keepId);
|
||||||
|
int deleted = ps.executeUpdate();
|
||||||
|
emit.accept(" 删除多余租户: " + deleted + " 个");
|
||||||
|
}
|
||||||
|
|
||||||
|
emit.accept(" [已迁移] " + id + ": 合并完成,保留 " + keepId);
|
||||||
|
recordMigration(id, "私有化合并多租户,保留最早租户 " + keepId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
emit.accept(" [错误] " + id + ": " + e.getMessage());
|
||||||
|
log.error("migration {} failed", id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── 重启核心 ────────────────────────────────────────────────────────────────
|
// ── 重启核心 ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void restartAndSelfUpdate(Consumer<String> emit, String composeFile) {
|
private void restartAndSelfUpdate(Consumer<String> emit, String composeFile) {
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户