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;
}
}