使用MySQL和JDBC运行.sql脚本


68

我开始将MySQL与JDBC一起使用。

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脚本?


4
您是否需要编写Java代码来运行这些create table语句的任何特定原因?它们以某种方式动态吗?
Vincent Ramdhanie 09年

因为他想用Java xD做所有事情
-Muskovets

Answers:


74

好。您可以在项目中使用此类(由于文件长而在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(”; \\“));”“ 因为你可能会得到stackoverflow.com/questions/3499483/...
gyorgyabraham

2
可以使用ResultSet它返回a还是仅对更新语句有效?我尝试使用它,但无法弄清楚如何返回它ResultSet。我会去的,Spring但是使用类比整个库要容易。
Alex Burdusel 2013年

稍微注意链接到脚本的链接-如果您的脚本具有类似代码“注释”select 1; -- do nothing的脚本,则脚本不会执行它,而是将其视为较长命令的前半部分(与新命令结合),其他副作用-如果这是文件中的最后一件事,它根本不会运行它]。如果您只使用单行sql注释就可以了
rogerdpack 2014年

5
此类无法处理程序
Muhamet Aljobairi 2015年

3
我随意复制代码,对其进行更新以添加对存储过程定界符的支持,将其上传到GitHub,并更新@jitter答案中的链接。
Benoit Duffez,2015年

26

我对此进行了大量研究,从春季开始发现了一个很好的工具。我认为使用SimpleJdbcTestUtils.executeSqlScript(...)实际上是最好的解决方案,因为它需要更多的维护和测试。

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


2
感谢@Amir Raminfar,您的回答帮助了我。无论如何,作为一个更新,spring已弃用SimpleJdbcTestUtil,建议JdbcTestUtils将来使用。
uthomas

1
这是最好的答案,Spring框架团队很活跃。
FBB 2013年

8
从Spring 4.0.3开始。JdbcTestUtils.executeSqlScript()现在不推荐使用这些方法。ScriptUtils.executeSqlScript(...)应该改为使用。
2014年

1
请注意,无论是否积极开发,这些实用程序类在设计时都考虑到了测试,对于大多数情况而言还不够;例如,由于定界符问题,它们不允许您创建存储过程;joe776的答案可能是一个更好的选择,具体取决于您的需求,
Haroldo_OK 2016年

16

Spring框架ResourceDatabasePopulator可能会有所帮助。正如您说的那样,您正在使用MySQL和JDBC,假设您已经DataSource准备好了一个由MySQL支持的实例。此外,我们假设您的MySQL脚本文件可在classpath中找到。假设您使用的是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();
    }

1
到目前为止,这里是最好的答案。我讨厌看到告诉您从命令行运行MySQL Dump Import的答案。在数据库位于其他服务器上的自动化环境中,效果不佳。
Zoidberg 2014年

@Zoidbergmysql命令行客户端,mysqldump可以在网络上正常工作,可以在自动脚本中使用。将数据库放置在其他服务器上应该没有问题。
Asaph 2015年

@Asaph你是正确的。我实际上尝试了上述解决方案,发现性能确实很慢。我使用命令行参数很好,所以上面的注释实际上是不正确的。
Zoidberg 2015年

6

对于用';'分隔的简单sql脚本 您可以使用此简单功能。它删除注释并逐一运行语句

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

2
您假设注释不能出现在单个语句中。在CREATE TABLE中这很常见。
Eyal Schneider 2014年

我会说更多。它不支持复杂的查询,但是您可以将分界符更改为其他内容,例如'; [\ s \ r \ n] * \\'。并根据需要使用评论。
lunicon 2014年

抱歉,但这个工作做得更好stackoverflow.com/questions/1497569/...
Atais

Atais,很高兴看到您的尝试...我的代码只是一个示例,请
按需


2

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

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

但是,在方法getString(int)的API文档中,提到索引以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 ,希望对您有用。


这非常有帮助。非常感谢你。

2

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


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


2

你能用这个吗?

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文件和数据库连接。然后,它使用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);
}

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。请阅读此操作指南以提供优质的答案。
thewaywere是

1

编写代码至:

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

如果这样做,我应该解析.sql文件。我原以为找不到jdbc的功能。
Macarse

1

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

JDBC驱动程序可以访问PL / SQL存储过程吗?

Oracle JDBC驱动程序常见问题有更多的信息:

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()方法。


问题的第一个链接已断开。
ceving 2013年


0

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

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

或者尝试使用ibatis中的ScriptRunner(com.ibatis.common.jdbc.ScriptRunner)。但是,仅包含整个库以运行脚本有点愚蠢。


1
对,是真的。无厘头添加一个lib只是运行一个脚本:(我认为这是很奇怪的是,JDBC并不附带类似的东西。
Macarse
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.