diff --git a/springboot-backend/src/main/java/com/admin/config/SQLiteConfig.java b/springboot-backend/src/main/java/com/admin/config/SQLiteConfig.java index 8d413da..550cc22 100644 --- a/springboot-backend/src/main/java/com/admin/config/SQLiteConfig.java +++ b/springboot-backend/src/main/java/com/admin/config/SQLiteConfig.java @@ -10,7 +10,12 @@ import org.springframework.stereotype.Component; import javax.annotation.PreDestroy; import javax.sql.DataSource; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.Statement; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; /** * SQLite 数据库配置 @@ -39,13 +44,98 @@ public class SQLiteConfig implements ApplicationRunner { statement.execute("PRAGMA temp_store=MEMORY;"); statement.execute("PRAGMA busy_timeout=5000;"); // 5秒超时 statement.execute("PRAGMA wal_autocheckpoint=1000;"); // 每1000页自动checkpoint - + + ensureNodeDualStackColumns(connection); + log.info("SQLite WAL mode configured successfully"); } catch (Exception e) { log.error("Failed to configure SQLite database", e); throw e; } } + + private void ensureNodeDualStackColumns(Connection connection) throws Exception { + Set cols = getTableColumns(connection, "node"); + if (cols.isEmpty()) { + return; + } + + ensureColumnIfMissing(connection, cols, "node", "server_ip_v4", "VARCHAR(100)"); + ensureColumnIfMissing(connection, cols, "node", "server_ip_v6", "VARCHAR(100)"); + + backfillNodeDualStackColumns(connection); + } + + private void backfillNodeDualStackColumns(Connection connection) throws Exception { + Pattern ipv4 = Pattern.compile("^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); + + try (Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery("SELECT id, server_ip, server_ip_v4, server_ip_v6 FROM node;"); + PreparedStatement updV4 = connection.prepareStatement("UPDATE node SET server_ip_v4 = ? WHERE id = ?;"); + PreparedStatement updV6 = connection.prepareStatement("UPDATE node SET server_ip_v6 = ? WHERE id = ?;") + ) { + while (rs.next()) { + long id = rs.getLong("id"); + String serverIp = rs.getString("server_ip"); + String v4 = rs.getString("server_ip_v4"); + String v6 = rs.getString("server_ip_v6"); + + if (serverIp == null || serverIp.isBlank()) { + continue; + } + if ((v4 != null && !v4.isBlank()) || (v6 != null && !v6.isBlank())) { + continue; + } + + String trimmed = serverIp.trim(); + + if (ipv4.matcher(trimmed).matches()) { + updV4.setString(1, trimmed); + updV4.setLong(2, id); + updV4.executeUpdate(); + } else { + long colonCount = trimmed.chars().filter(ch -> ch == ':').count(); + if (colonCount >= 2) { + updV6.setString(1, trimmed); + updV6.setLong(2, id); + updV6.executeUpdate(); + } + } + } + } + } + + private Set getTableColumns(Connection connection, String table) throws Exception { + Set cols = new HashSet<>(); + try (Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery("PRAGMA table_info(" + table + ");")) { + while (rs.next()) { + String name = rs.getString("name"); + if (name != null && !name.isBlank()) { + cols.add(name); + } + } + } + return cols; + } + + private void ensureColumnIfMissing( + Connection connection, + Set existingColumns, + String table, + String column, + String type + ) throws Exception { + if (existingColumns.contains(column)) { + return; + } + + try (Statement statement = connection.createStatement()) { + statement.execute("ALTER TABLE " + table + " ADD COLUMN " + column + " " + type + ";"); + } + + log.info("SQLite schema updated: added {}.{}", table, column); + } /** * 定期执行 checkpoint,确保 WAL 文件内容写入主数据库 @@ -80,4 +170,3 @@ public class SQLiteConfig implements ApplicationRunner { } } } -