72

I am starting to use MySQL with 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)" +
            ")");

I have 3-4 tables to create and this doesn't look good.

Is there a way to run a .sql script from MySQL JDBC?

2
  • 4
    any particular reason why you need to write java code to run these create table statements? Are they dynamic in some way? Commented Jun 25, 2009 at 14:21
  • because he wants to do all stuff by Java xD Commented Oct 20, 2018 at 8:28

13 Answers 13

78

Ok. You can use this class here (posted on pastebin because of file length) in your project. But remember to keep the apache license info.

JDBC ScriptRunner

It's ripoff of the iBatis ScriptRunner with dependencies removed.

You can use it like this

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

That's it!

Sign up to request clarification or add additional context in comments.

6 Comments

Very handful class. I must add that line 130 can cause headaches. I replaced it to "String trimmedLine = line.trim().replaceAll(";$", Matcher.quoteReplacement("; \\"));" because you might get stackoverflow.com/questions/3499483/…
Can this be used to return a ResultSet or it only works for update statements? I tried using it but cannot figure how to get it to return a ResultSet. I would go for Spring but it is easier to use a class than an entire library.
be careful with the linked to script a bit--if your script has a code "comment" like select 1; -- do nothing then the script doesn't execute it but treats it like the first half of a longer command [concatenated with the new command] other side effect--if that's the last thing in your file, it doesn't run it at all]. If you just stick with single line sql comments it's ok
this class can't handle PROCEDURE ever
I took the liberty to copy the code, update it to add support for delimiters for stored procedures, upload it to GitHub, and update the link in @jitter's answer.
|
26

I did a lot of research on this and found a good util from spring. I think using SimpleJdbcTestUtils.executeSqlScript(...) is actually the best solution, as it is more maintained and tested.

Edit: SimpleJdbcTestUtils is deprecated. You should use JdbcTestUtils. Updated the link.

4 Comments

Thanks @Amir Raminfar, your answer helped me out. Anyway just as an update, spring deprecated SimpleJdbcTestUtil and advises to use JdbcTestUtils in future.
This is the best answer, the Spring framework team is active.
Starting from Spring 4.0.3. JdbcTestUtils.executeSqlScript() methods are now deprecated. ScriptUtils.executeSqlScript(...) should be used instead.
Please note that, actively developed or not, those utility classes were designed with testing in mind, and won't be sufficient for most cases; for example, they won't allow you to create a stored procedure due to delimiter problems; joe776's answer may be a better option, depending on your need,
18

Spring Framework's ResourceDatabasePopulator may help. As you said you're using MySQL and JDBC, let's assume you have a MySQL-backed DataSource instance ready. Further, let's assume your MySQL script files are classpath-locatable. Let's assume you are using WAR layout and the script files are located in a directory src/main/webapp/resources/mysql-scripts/... or src/test/resources/mysql-scripts/.... Then you can use ResourceDatabasePopulator to execute SQL scripts like this:

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

3 Comments

By far the best answer here. I get tired of seeing the answers that tell you to run the MySQL dump import from the command line. Doesn't work so well in an automated environment where the database is on a different server.
@Zoidberg The mysql command line client and mysqldump work fine over a network and can be used in automated scripts. Having the database on a different server should pose no issue.
@Asaph You are correct. I actually tried the above solution and found the performance was really slow. I got it working with the command line argument just fine, so my above comment is actually incorrect.
6

For simple sql script splitted by ';' you can use this simple function. It remove comments and run statements one by one

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

4 Comments

You are assuming that comments can't appear inside of a single statement. In CREATE TABLE this is common.
I will say even more. It does not support complex queries, but you can change delimeter to something else like ';[\s\r\n]*\\'. and use comments as you like.
sorry but this one work better stackoverflow.com/questions/1497569/…
Atais, glad to see your attemps... my code is just an example, use it you wish :)
5

@Pantelis Sopasakis

Slightly modified version on GitHub: https://gist.github.com/831762/

Its easier to track modifications there.

1 Comment

After fixing the bug in the comment on this gist, this appears to work so far!
2

Regarding SQL script runner (which I'm also using), I noticed the following piece of code:

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

However, in the API documentation for the method getString(int) it's mentioned that indexes start with 1, so this should become:

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

Second, this implementation of ScriptRunner does not provide support for DELIMITER statements in the SQL script which are important if you need to compile TRIGGERS or PROCEDURES. So I have created this modified version of ScriptRunner: http://pastebin.com/ZrUcDjSx which I hope you'll find useful.

Comments

2

Another interesting option would be to use Jisql to run the scripts. Since the source code is available, it should be possible to embed it into an application.


Edit: took a careful look at it; embedding it inside something else would require some modification to its source code.

Comments

2

Can you use this:

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

This function gets SQL file and DB connection. Then it reads the file line-by-line using BufferedReader from java.io.
And, finally, executes the read statements.

Java 8+ version:

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

1 Comment

While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. Please read this how-to-answer for providing quality answer.
1

Write code to:

  1. Read in a file containing a number of SQL statements.
  2. Run each SQL statement.

1 Comment

If I do it like that I should parse the .sql file. I was expecting there was a jdbc's fuction which I couldn't find.
1

For Oracle PL/SQL, the Oracle JDBC-driver indeed supports executing entire SQL-scripts including stored procedures and anonymous blocks (PL/SQL specific notation), see

Can the JDBC Drivers access PL/SQL Stored Procedures?

The Oracle JDBC driver FAQ has more info:

Oracle JDBC drivers support execution of PL/SQL stored procedures and anonymous blocks. They support both SQL92 escape syntax and Oracle PL/SQL block syntax. The following PL/SQL calls would work with any Oracle JDBC driver:

// 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

It should be possible to read in a file and feed the content to the prepareCall()-method.

1 Comment

The first link to the question is broken.
1

Maven SQL Plugin Use this plugin to execute SQL statements a file or list of files through

  1. sqlCommand
  2. srcFiles 3.fileset configurations

Comments

0

There isn't really a way to do this.

You could either run the mysql command line client via Runtime.exec(String[]) and read this article when you decide for this option

Or try using the ScriptRunner (com.ibatis.common.jdbc.ScriptRunner) from ibatis. But it's a bit stupid to include a whole library just to run a script.

1 Comment

Yes, it's true. Doesn't make sense to add a lib just to run a script :( I think it's quite strange that jdbc doesn't come with something like that.
0

Here's a quick and dirty solution that worked for me.

public void executeScript(File scriptFile) {
  Connection connection = null;
  try {
    connection = DriverManager.getConnection(url, user, password);
    if(scriptFile.exists()) {
      var buffer = new StringBuilder();
      var scanner = new Scanner(scriptFile);
      while(scanner.hasNextLine()) {
        var line = scanner.nextLine();
        buffer.append(line);
        // If we encounter a semicolon, then that's a complete statement, so run it.
        if(line.endsWith(";")) {
          String command = buffer.toString();
          connection.createStatement().execute(command);
          buffer = new StringBuilder();
        } else { // Otherwise, just append a newline and keep scanning the file.
          buffer.append("\n");
        }
     }
    }
    else System.err.println("File not found.");
  } catch (SQLException e) {
    e.printStackTrace();
} finally {
  if(connection != null) connection.close();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.