Как выполнить файл сценария SQL в Java?

Я хочу выполнить файл сценария SQL на Java без чтения всего содержимого файла в большой запрос и его выполнения.

есть ли другой стандартный способ?

9 ответов


нет переносимый способ сделать это. Вы можете выполнить собственный клиент как внешнюю программу, чтобы сделать это, хотя:

import java.io.*;
public class CmdExec {

  public static void main(String argv[]) {
    try {
      String line;
      Process p = Runtime.getRuntime().exec
        ("psql -U username -d dbname -h serverhost -f scripfile.sql");
      BufferedReader input =
        new BufferedReader
          (new InputStreamReader(p.getInputStream()));
      while ((line = input.readLine()) != null) {
        System.out.println(line);
      }
      input.close();
    }
    catch (Exception err) {
      err.printStackTrace();
    }
  }
}
  • пример кода был извлечен из здесь и изменен, чтобы ответить на вопрос, предполагая, что пользователь хочет выполнить файл сценария с PostgreSQL.

существует отличный способ выполнения SQL-скриптов с Java, не читая их самостоятельно, пока вы не возражаете иметь зависимость от Ant. На мой взгляд, такая зависимость очень хорошо оправдана в вашем случае. Вот пример кода, где класс SQLExec живет в ant.jar:

private void executeSql(String sqlFilePath) {
    final class SqlExecuter extends SQLExec {
        public SqlExecuter() {
            Project project = new Project();
            project.init();
            setProject(project);
            setTaskType("sql");
            setTaskName("sql");
        }
    }

    SqlExecuter executer = new SqlExecuter();
    executer.setSrc(new File(sqlFilePath));
    executer.setDriver(args.getDriver());
    executer.setPassword(args.getPwd());
    executer.setUserid(args.getUser());
    executer.setUrl(args.getUrl());
    executer.execute();
}

нет, вы должны прочитать файл, разделить его на отдельные запросы, а затем выполнить их по отдельности (или с помощью пакетного API JDBC).

одна из причин заключается в том, что каждая база данных определяет свой собственный способ разделения операторов SQL (некоторые используют ;, другие /, некоторые позволяют одновременно или даже определить свой собственный разделитель).


вы не можете использовать JDBC, поскольку он не поддерживает . Работа вокруг будет включать в себя iBatis iBATIS-это структура персистентности и вызов Scriptrunner конструктор как показано в iBatis документация .

нехорошо включать тяжелую структуру персистентности, такую как ibatis, чтобы запускать простые сценарии sql любыми способами, которые вы можете сделать с помощью командной строки

$ mysql -u root -p db_name < test.sql

библиотека Flyway действительно хороша для этого:

    Flyway flyway = new Flyway();
    flyway.setDataSource(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword());
    flyway.setLocations("classpath:db/scripts");
    flyway.clean();
    flyway.migrate();

это сканирует местоположения для сценариев и запускает их по порядку. Скрипты могут быть версионными с именем V01__.sql, поэтому, если вызывается только миграция, будут выполняться только те, которые еще не запущены. Использует таблицу под названием "schema_version" для отслеживания вещей. Но может делать и другие вещи, см. документы:flyway.

чистый вызов не требуется, но полезно начать с чистого DB. Также следует учитывать местоположение (по умолчанию "classpath: db/migration"), нет места после":", который поймал меня.


поскольку JDBC не поддерживает эту опцию, лучшим способом решить этот вопрос является выполнение командных строк через программу Java. Ниже приведен пример для postgresql:

private void executeSqlFile() {
     try {
         Runtime rt = Runtime.getRuntime();
         String executeSqlCommand = "psql -U (user) -h (domain) -f (script_name) (dbName)";
         Process pr = rt.exec();
         int exitVal = pr.waitFor();
         System.out.println("Exited with error code " + exitVal);
      } catch (Exception e) {
        System.out.println(e.toString());
      }
}

самый простой внешний инструмент, который я нашел, который также переносим, - jisql -https://www.xigole.com/software/jisql/jisql.jsp . Вы бы запустили его как:

java -classpath lib/jisql.jar:\
          lib/jopt-simple-3.2.jar:\
          lib/javacsv.jar:\
           /home/scott/postgresql/postgresql-8.4-701.jdbc4.jar 
    com.xigole.util.sql.Jisql -user scott -password blah     \
    -driver postgresql                                       \
    -cstring jdbc:postgresql://localhost:5432/scott -c \;    \
    -query "select * from test;"

JDBC не поддерживает эту опцию (хотя конкретный драйвер БД может предложить это). Во всяком случае, не должно быть проблем с загрузкой всего содержимого файла в память.


попробуйте этот код:

String strProc =
         "DECLARE \n" +
         "   sys_date DATE;"+
         "" +
         "BEGIN\n" +
         "" +
         "   SELECT SYSDATE INTO sys_date FROM dual;\n" +
         "" +
         "END;\n";

try{
    DriverManager.registerDriver ( new oracle.jdbc.driver.OracleDriver () );
    Connection connection = DriverManager.getConnection ("jdbc:oracle:thin:@your_db_IP:1521:your_db_SID","user","password");  
    PreparedStatement psProcToexecute = connection.prepareStatement(strProc);
    psProcToexecute.execute();
}catch (Exception e) {
    System.out.println(e.toString());  
}