diff --git a/tenant-service/src/main/java/com/xuqm/tenant/config/PrivateDeploymentProperties.java b/tenant-service/src/main/java/com/xuqm/tenant/config/PrivateDeploymentProperties.java index 729fda5..dccc3f8 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/config/PrivateDeploymentProperties.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/config/PrivateDeploymentProperties.java @@ -23,12 +23,12 @@ public class PrivateDeploymentProperties { public String getMode() { return 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) { this.tenantRegisterEnabled = tenantRegisterEnabled; } - public boolean isTenantBootstrapEnabled() { return tenantBootstrapEnabled; } + public boolean isTenantBootstrapEnabled() { return isPrivate() ? true : tenantBootstrapEnabled; } public void setTenantBootstrapEnabled(boolean tenantBootstrapEnabled) { this.tenantBootstrapEnabled = tenantBootstrapEnabled; } diff --git a/tenant-service/src/main/java/com/xuqm/tenant/service/SystemUpdateService.java b/tenant-service/src/main/java/com/xuqm/tenant/service/SystemUpdateService.java index abc108c..38e373d 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/service/SystemUpdateService.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/service/SystemUpdateService.java @@ -7,6 +7,8 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; +import com.xuqm.tenant.config.PrivateDeploymentProperties; + import javax.sql.DataSource; import java.io.BufferedReader; import java.io.IOException; @@ -47,9 +49,11 @@ public class SystemUpdateService { private String deployRoot; private final DataSource dataSource; + private final PrivateDeploymentProperties deployProps; - public SystemUpdateService(DataSource dataSource) { + public SystemUpdateService(DataSource dataSource, PrivateDeploymentProperties deployProps) { this.dataSource = dataSource; + this.deployProps = deployProps; } // ── 公开接口 ──────────────────────────────────────────────────────────────── @@ -409,6 +413,7 @@ public class SystemUpdateService { migrate_v20260101_drop_device_id_unique_index(emit); migrate_v20260527_push_license_operation_logs(emit); + migrate_v20260527_consolidate_private_tenants(emit); // 新版本迁移在此追加,例如: // migrate_v20260601_add_app_extra_column(emit); @@ -509,6 +514,96 @@ public class SystemUpdateService { recordMigration(id, "push-service 和 license-service 新增操作日志表"); } + /** + * 私有化部署下合并多租户:保留最早的租户,将其余租户的 tenant_id 全部替换,然后删除多余租户。 + * 仅在 DEPLOYMENT_MODE=PRIVATE 时执行。 + */ + private void migrate_v20260527_consolidate_private_tenants(Consumer 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 emit, String composeFile) {