使用带有 JDBC 的 MySQL 运行 .sql 脚本

Posted

技术标签:

【中文标题】使用带有 JDBC 的 MySQL 运行 .sql 脚本【英文标题】:Running a .sql script using MySQL with JDBC 【发布时间】:2010-11-05 20:43:17 【问题描述】:

我开始使用带有 JDBC 的 mysql

Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///x", "x", "x");
stmt = conn.createStatement();
stmt.execute( "CREATE TABLE amigos" +
            "("+
            "id          int AUTO_INCREMENT          not null,"+
            "nombre      char(20)                    not null,"+
            "primary key(id)" +
            ")");

我要创建 3-4 个表,这看起来不太好。

有没有办法从 MySQL JDBC 运行 .sql 脚本?

【问题讨论】:

您需要编写 java 代码来运行这些创建表语句的任何特殊原因?它们在某种程度上是动态的吗? 因为他想用 Java xD 做所有的事情 【参考方案1】:

你能用这个吗:

public static void executeSQL(File f, Connection c) throws Exception 
    BufferedReader br = new BufferedReader(new FileReader(f));
    String sql = "", line;
    while ((line = br.readLine()) != null) sql += (line+"\n");
    c.prepareCall(sql).execute(sql);

此函数获取 SQL 文件和 DB 连接。 然后它使用 java.io 中的 BufferedReader 逐行读取文件。 最后,执行读取语句。

Java 8+ 版本:

public static void executeSQL(Path p, Connection c) throws Exception 
    List<String> lines = Files.readAllLines(p);
    String s = String.join("\n", lines.toArray(new String[0]));
    c.prepareCall(s).execute(s);

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。请阅读此how-to-answer 以提供高质量的答案。【参考方案2】:

另一个有趣的选择是使用Jisql 来运行脚本。由于源代码可用,应该可以将其嵌入到应用程序中。


编辑:仔细看了一下;将其嵌入到其他东西中需要对其源代码进行一些修改。

【讨论】:

【参考方案3】:

好的。你可以在你的项目中使用这个类(由于文件长度而发布在 pastebin 上)。但请记住保留 apache 许可证信息。

JDBC ScriptRunner

它是对 iBatis ScriptRunner 的剽窃,移除了依赖项。

你可以这样使用它

Connection con = ....
ScriptRunner runner = new ScriptRunner(con, [booleanAutoCommit], [booleanStopOnerror]);
runner.runScript(new BufferedReader(new FileReader("test.sql")));

就是这样!

【讨论】:

非常少的一类。我必须补充一点,第 130 行可能会引起头痛。我将其替换为“String trimmedLine = line.trim().replaceAll(";$", Matcher.quoteReplacement("; \\"));"因为你可能会得到***.com/questions/3499483/… 这可以用于返回ResultSet 还是仅适用于更新语句?我尝试使用它,但不知道如何让它返回ResultSet。我会选择Spring,但使用一个类比使用整个库更容易。 对链接到脚本要小心一点——如果你的脚本有一个像select 1; -- do nothing这样的代码“注释”,那么脚本不会执行它,而是把它当作更长的前半部分命令 [与新命令连接] 其他副作用——如果这是文件中的最后一件事,它根本不会运行它]。如果你只是坚持使用单行 sql cmets 没关系 这个类永远无法处理 PROCEDURE 我冒昧地复制代码,更新它以添加对存储过程分隔符的支持,将其上传到 GitHub,并更新@jitter 答案中的链接。【参考方案4】:

对于用';'分割的简单sql脚本你可以使用这个简单的功能。 它删除 cmets 并逐个运行语句

  static void executeScript(Connection conn, InputStream in)
    throws SQLException
  
    Scanner s = new Scanner(in);
    s.useDelimiter("/\\*[\\s\\S]*?\\*/|--[^\\r\\n]*|;");

    Statement st = null;

    try
    
      st = conn.createStatement();

      while (s.hasNext())
      
        String line = s.next().trim();

        if (!line.isEmpty())
          st.execute(line);
      
    
    finally
    
      if (st != null)
        st.close();
    
  

【讨论】:

您假设 cmets 不能出现在单个语句中。在 CREATE TABLE 中这很常见。 我会说更多。它不支持复杂查询,但您可以将分隔符更改为其他内容,例如 ';[\s\r\n]*\\'。并根据需要使用 cmets。 抱歉,这个效果更好***.com/questions/1497569/… Atais,很高兴看到你的尝试......我的代码只是一个例子,你可以使用它:)【参考方案5】:

我对此做了很多研究,发现了一个很好的util from spring。我认为使用SimpleJdbcTestUtils.executeSqlScript(...) 实际上是最好的解决方案,因为它得到了更多的维护和测试。

编辑:SimpleJdbcTestUtils 已弃用。你应该使用JdbcTestUtils。更新了链接。

【讨论】:

感谢@Amir Raminfar,您的回答帮助了我。无论如何,作为更新,spring 弃用了SimpleJdbcTestUtil,并建议将来使用JdbcTestUtils 这是最好的答案,Spring 框架团队很活跃。 从 Spring 4.0.3 开始。 JdbcTestUtils.executeSqlScript() 方法现已弃用。应该改用ScriptUtils.executeSqlScript(...) 请注意,无论是否积极开发,这些实用程序类在设计时都考虑到了测试,并且对于大多数情况来说是不够的;例如,由于分隔符问题,它们不允许您创建存储过程; joe776's answer 可能是更好的选择,这取决于您的需要,【参考方案6】:

Maven SQL Plugin使用这个插件通过一个文件或者文件列表执行SQL语句

    sqlCommand src 文件 3.文件集配置

【讨论】:

【参考方案7】:

Spring Framework 的ResourceDatabasePopulator 可能会有所帮助。正如您所说,您正在使用 MySQL 和 JDBC,假设您已准备好由 MySQL 支持的 DataSource 实例。此外,假设您的 MySQL 脚本文件是类路径可定位的。假设您正在使用 WAR 布局,并且脚本文件位于目录 src/main/webapp/resources/mysql-scripts/...src/test/resources/mysql-scripts/... 中。然后你可以使用ResourceDatabasePopulator 来执行这样的SQL脚本:

import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import javax.sql.DataSource;

DataSource dataSource = getYourMySQLDriverBackedDataSource();

ResourceDatabasePopulator rdp = new ResourceDatabasePopulator();    
rdp.addScript(new ClassPathResource(
                        "mysql-scripts/firstScript.sql"));
rdp.addScript(new ClassPathResource(
                        "mysql-scripts/secondScript.sql"));

try 
        Connection connection = dataSource.getConnection();
        rdp.populate(connection); // this starts the script execution, in the order as added
     catch (SQLException e) 
        e.printStackTrace();
    

【讨论】:

到目前为止最好的答案在这里。我厌倦了看到告诉您从命令行运行 MySQL 转储导入的答案。在数据库位于不同服务器上的自动化环境中效果不佳。 @Zoidberg mysql 命令行客户端和mysqldump 在网络上运行良好,可以在自动化脚本中使用。将数据库放在不同的服务器上应该没有问题。 @Asaph 你是对的。我实际上尝试了上述解决方案,发现性能真的很慢。我可以很好地使用命令行参数,所以我上面的评论实际上是不正确的。【参考方案8】:

@Pantelis Sopasakis

GitHub上略有修改的版本:https://gist.github.com/831762/

在那里更容易跟踪修改。

【讨论】:

在修复了这个要点的评论中的错误之后,这似乎工作到目前为止!【参考方案9】:

关于 SQL 脚本运行器(我也在使用),我注意到以下代码:

for (int i = 0; i < cols; i++) 
  String value = rs.getString(i);
  print(value + "\t");

但是,在方法 getString(int) 的 API 文档中提到了 indexes start with 1,所以应该变成:

for (int i = 1; i <= cols; i++) 
  String value = rs.getString(i);
  print(value + "\t");

其次,ScriptRunner 的这个实现不支持 SQL 脚本中的 DELIMITER 语句,如果您需要编译 TRIGGERS 或 PROCEDURES,这些语句很重要。所以我创建了这个修改版的 ScriptRunner:http://pastebin.com/ZrUcDjSx,希望对你有用。

【讨论】:

这很有帮助。非常感谢。【参考方案10】:

对于 Oracle PL/SQL,Oracle JDBC 驱动程序确实支持执行整个 SQL 脚本,包括存储过程和匿名块(PL/SQL 特定符号),请参阅

Can the JDBC Drivers access PL/SQL Stored Procedures?

Oracle JDBC driver FAQ 有更多信息:

Oracle JDBC 驱动程序支持执行 PL/SQL 存储过程和 匿名块。他们都支持 SQL92 转义语法和 Oracle PL/SQL 块语法。以下 PL/SQL 调用适用于任何 Oracle JDBC 司机:

// SQL92 syntax
CallableStatement cs1 = conn.prepareCall
                       ( "call proc (?,?)" ) ; // stored proc
CallableStatement cs2 = conn.prepareCall
                       ( "? = call func (?,?)" ) ; // stored func
// Oracle PL/SQL block syntax
CallableStatement cs3 = conn.prepareCall
                       ( "begin proc (?,?); end;" ) ; // stored proc
CallableStatement cs4 = conn.prepareCall
                       ( "begin ? := func(?,?); end;" ) ; // stored func

应该可以读取文件并将内容提供给 prepareCall() 方法。

【讨论】:

问题的第一个链接已损坏。【参考方案11】:

真的没有办法做到这一点。

当您决定使用此选项时,您可以通过 Runtime.exec(String[]) 运行 mysql 命令行客户端并阅读 this article

或者尝试使用来自ibatis 的 ScriptRunner (com.ibatis.common.jdbc.ScriptRunner)。但是为了运行脚本而包含整个库有点愚蠢。

【讨论】:

是的,这是真的。仅仅为了运行一个脚本而添加一个库是没有意义的:(我认为 jdbc 没有这样的东西很奇怪。【参考方案12】:

将代码写入:

    读入包含多个 SQL 语句的文件。 运行每个 SQL 语句。

【讨论】:

如果我这样做,我应该解析 .sql 文件。我期待有一个我找不到的 jdbc 功能。

以上是关于使用带有 JDBC 的 MySQL 运行 .sql 脚本的主要内容,如果未能解决你的问题,请参考以下文章

ava基础MySQL存储过程 Java基础 JDBC连接MySQL数据库

jmeter jdbc request 如何运行多个sql

Spring JDBC 在运行 SQL 脚本时无法处理 DECLARE 语句

带有 maven 的 mysql 连接器:java.lang.NoClassDefFoundError: com/mysql/jdbc/Driver

使用 JDBC 取消 SQL 语句

带有 JDBC 的 Java SQLException - SQLITE_MISUSE