import java.sql.*; import java.util.ArrayList; import java.util.List; /** * 批量更新菜单名:「租户语义关键词」→「语义关键词」(menu_id=29933) * * 影响范围: * 主库: * 1. sys_menu (admin 总后台菜单) * 2. tenant_sys_menu (租户管理端模板表) * 3. tenant_company_menu (租户销售端模板表) * 各租户库: * 4. sys_menu (租户管理端菜单) * 5. company_menu (租户销售端菜单) * * 用法: * java RenameLobsterSemanticMenu dry-run # 仅预览 * java RenameLobsterSemanticMenu # 真实执行 */ public class RenameLobsterSemanticMenu { private static final long MENU_ID = 29933L; private static final String OLD_NAME = "租户语义关键词"; private static final String NEW_NAME = "语义关键词"; private static final String MASTER_HOST = getenv("DB_HOST", "cq-cdb-8fjmemkb.sql.tencentcdb.com"); private static final int MASTER_PORT = Integer.parseInt(getenv("DB_PORT", "27220")); private static final String MASTER_USER = getenv("DB_USER", "root"); private static final String MASTER_PASSWORD = getenv("DB_PASSWORD", "Ylrz_1q2w3e4r5t6y"); private static final String MASTER_DB = getenv("DB_NAME", "ylrz_saas"); public static void main(String[] args) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); boolean dryRun = args.length > 0 && "dry-run".equalsIgnoreCase(args[0]); System.out.println("=== 重命名菜单: 「" + OLD_NAME + "」→「" + NEW_NAME + "」 (menu_id=" + MENU_ID + ") ==="); System.out.println("dryRun=" + dryRun); int masterOk = 0; int tenantOk = 0; int tenantSkip = 0; int tenantFail = 0; // ===== 1. 主库 ===== System.out.println("\n[MASTER] " + MASTER_DB); try (Connection master = open(MASTER_HOST, MASTER_PORT, MASTER_DB, MASTER_USER, MASTER_PASSWORD)) { masterOk += updateMenu(master, "sys_menu", dryRun); masterOk += updateMenu(master, "tenant_sys_menu", dryRun); masterOk += updateMenu(master, "tenant_company_menu", dryRun); } catch (Exception e) { System.out.println(" [ERR] " + e.getMessage()); } // ===== 2. 各租户库 ===== List tenantIds; try (Connection master = open(MASTER_HOST, MASTER_PORT, MASTER_DB, MASTER_USER, MASTER_PASSWORD)) { tenantIds = loadActiveTenantIds(master); } for (Long tenantId : tenantIds) { TenantDb tenant; try (Connection master = open(MASTER_HOST, MASTER_PORT, MASTER_DB, MASTER_USER, MASTER_PASSWORD)) { tenant = loadTenant(master, tenantId); } if (tenant == null) { tenantSkip++; continue; } System.out.println("\n[TENANT " + tenantId + "] " + tenant.database); try (Connection conn = open(tenant.host, tenant.port, tenant.database, tenant.user, tenant.password)) { int n = updateMenu(conn, "sys_menu", dryRun); if (n > 0) tenantOk++; int m = updateMenu(conn, "company_menu", dryRun); if (m > 0) tenantOk++; if (n == 0 && m == 0) tenantSkip++; } catch (Exception e) { System.out.println(" [ERR] " + e.getMessage()); tenantFail++; } } System.out.println("\n=== SUMMARY ==="); System.out.println("Master updated=" + masterOk); System.out.println("Tenant updated=" + tenantOk + " SKIP=" + tenantSkip + " FAIL=" + tenantFail); if (tenantFail > 0) { System.exit(1); } } /** * 更新指定菜单表中的菜单名。 * 返回受影响的行数。 */ private static int updateMenu(Connection conn, String table, boolean dryRun) throws SQLException { if (!tableExists(conn, table)) { System.out.println(" [SKIP] no " + table); return 0; } // 先查询当前菜单名 String currentName = null; try (PreparedStatement ps = conn.prepareStatement( "SELECT menu_name FROM " + table + " WHERE menu_id = ? LIMIT 1")) { ps.setLong(1, MENU_ID); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { currentName = rs.getString(1); } } } if (currentName == null) { System.out.println(" [SKIP] " + table + ": menu_id=" + MENU_ID + " not found"); return 0; } if (NEW_NAME.equals(currentName)) { System.out.println(" [SKIP] " + table + ": already renamed to '" + NEW_NAME + "'"); return 0; } System.out.println(" " + table + ": '" + currentName + "' -> '" + NEW_NAME + "'"); if (dryRun) { return 1; } String sql = "UPDATE " + table + " SET menu_name = ?, update_time = NOW() WHERE menu_id = ?"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, NEW_NAME); ps.setLong(2, MENU_ID); return ps.executeUpdate(); } } private static boolean tableExists(Connection conn, String table) throws SQLException { try (ResultSet rs = conn.getMetaData().getTables(null, null, table, null)) { return rs.next(); } } private static List loadActiveTenantIds(Connection master) throws SQLException { List ids = new ArrayList<>(); try (Statement st = master.createStatement(); ResultSet rs = st.executeQuery("SELECT id FROM tenant_info WHERE status = 1 ORDER BY id")) { while (rs.next()) { ids.add(rs.getLong(1)); } } return ids; } private static TenantDb loadTenant(Connection master, long tenantId) throws SQLException { try (PreparedStatement ps = master.prepareStatement( "SELECT db_url, db_account, db_pwd FROM tenant_info WHERE id = ? AND status = 1 LIMIT 1")) { ps.setLong(1, tenantId); try (ResultSet rs = ps.executeQuery()) { if (!rs.next()) { return null; } return parseJdbcUrl(rs.getString("db_url"), rs.getString("db_account"), rs.getString("db_pwd")); } } } private static TenantDb parseJdbcUrl(String jdbcUrl, String user, String password) { String body = jdbcUrl.substring("jdbc:mysql://".length()); int slash = body.indexOf('/'); String hostPort = body.substring(0, slash); String rest = body.substring(slash + 1); int q = rest.indexOf('?'); String database = q >= 0 ? rest.substring(0, q) : rest; int colon = hostPort.indexOf(':'); TenantDb t = new TenantDb(); t.host = colon >= 0 ? hostPort.substring(0, colon) : hostPort; t.port = colon >= 0 ? Integer.parseInt(hostPort.substring(colon + 1)) : 3306; t.database = database; t.user = user != null ? user : MASTER_USER; t.password = password != null ? password : MASTER_PASSWORD; return t; } private static Connection open(String host, int port, String database, String user, String password) throws SQLException { return DriverManager.getConnection( "jdbc:mysql://" + host + ":" + port + "/" + database + "?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowMultiQueries=true", user, password); } private static String getenv(String key, String defaultValue) { String v = System.getenv(key); return v != null && !v.isEmpty() ? v : defaultValue; } private static final class TenantDb { String host; int port; String database; String user; String password; } }