import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * 把一个 .sql 文件按语句逐条执行(备份文件与一次性 DDL 用)。 * *

不处理 DELIMITER:Flyway 自己的迁移文件由 Flyway 执行,这里只跑不含存储过程的脚本。 * 用法:java RunSqlFile <jdbc-url> <file.sql> */ public class RunSqlFile { public static void main(String[] args) throws Exception { String url = args[0]; Path file = Path.of(args[1]); List statements = split(Files.readString(file, StandardCharsets.UTF_8)); int failed = 0; try (Connection connection = DriverManager.getConnection(url, "root", "123456")) { try (Statement statement = connection.createStatement()) { for (String sql : statements) { try { statement.execute(sql); } catch (Exception exception) { failed++; String head = sql.length() > 120 ? sql.substring(0, 120) + "..." : sql; System.out.println("!! 失败:" + exception.getMessage()); System.out.println(" " + head.replace('\n', ' ')); } } } } System.out.println("执行语句 " + statements.size() + " 条,失败 " + failed + " 条"); } /** 按行尾分号切分,并支持 {@code DELIMITER} 指令(迁移里的存储过程需要)。跳过空语句与纯注释块。 */ private static List split(String content) { List statements = new ArrayList<>(); StringBuilder current = new StringBuilder(); String delimiter = ";"; for (String line : content.split("\n")) { String trimmed = line.trim(); String upper = trimmed.toUpperCase(java.util.Locale.ROOT); if (upper.startsWith("DELIMITER ")) { delimiter = trimmed.substring("DELIMITER ".length()).trim(); continue; } if (trimmed.startsWith("--") && current.toString().isBlank()) continue; current.append(line).append('\n'); if (trimmed.endsWith(delimiter)) { String sql = current.toString().trim(); String withoutTrailing = sql.substring(0, sql.length() - delimiter.length()).trim(); if (!withoutTrailing.isBlank() && !withoutTrailing.startsWith("--")) statements.add(withoutTrailing); current.setLength(0); } } return statements; } }