2008-10-14 5 views
9

У меня есть куча sql-скриптов, которые должны обновить базу данных при запуске java-приложения.run oracle sql script из java

Я пробовал использовать скрипт ibatis, но он не славен при определении триггеров, где «;» символ не обозначает конец инструкции.

Теперь я написал свою собственную версию бегуна сценария, которая в основном выполняет эту работу, но уничтожает возможное форматирование и комментарии, особенно в «создании или замене вида».

public class ScriptRunner { 
private final DataSource ds; 


public ScriptRunner(DataSource ds) { 
    this.ds = ds; 
} 

public void run(InputStream sqlStream) throws SQLException, IOException { 
    sqlStream.reset(); 
    final Statement statement = ds.getConnection().createStatement(); 
    List<String> sqlFragments = createSqlfragments(sqlStream); 
    for (String toRun : sqlFragments) { 
     if (toRun.length() > 0) { 
      statement.execute(toRun); 
     } 
    } 
} 

private static List<String> createSqlfragments(InputStream sqlStream) throws IOException { 
    BufferedReader br = new BufferedReader(new InputStreamReader(sqlStream)); 

    List<String> ret = new ArrayList<String>(); 
    String line; 
    StringBuilder script = new StringBuilder(); 
    while ((line = br.readLine()) != null) { 
     if (line.equals("/")) { 
      ret.add(removeMultilineComments(script)); 
      script = new StringBuilder(); 
     } else { 
      //strip comments 
      final int indexComment = line.indexOf("--"); 
      String lineWithoutComments = (indexComment != -1) ? line.substring(0, indexComment) : line; 
      script.append(lineWithoutComments).append(" "); 
     } 
    } 
    if (script.length() > 0) { 
     ret.add(removeMultilineComments(script)); 
    } 
    return ret; 
} 

private static String removeMultilineComments(StringBuilder script) { 
    return script.toString().replaceAll("/\\*(.*?)\\*/", "").trim(); 
} 

есть ли чистый способ удержать это? есть ли что-то в спящем режиме, которого я не видел? или я могу как-то передать входной поток в sqlplus? Кроме того, я беспокоюсь о форматировании, я сомневаюсь, что этот код является безошибочным, так как у меня ограниченные знания о синтаксисе pl/sql.

ответ

2

sqlplus: да, вы можете. Я все время запускаю sqlplus из Xemacs (editor). Таким образом, вы можете запустить sqlplus в интерпретируемом режиме, а затем предоставить ему команды и прочитать результат.

Другим способом является загрузка бесплатного инструмента разработчика SQL на основе Java из oracle (http://www.oracle.com/technology/software/products/sql/index.html). он поставляется с утилитой sqlcli.bat, которая является оболочкой над java-программой. Вы можете использовать эту утилиту командной строки для выполнения своей работы.

резюме, я бы попытался запустить sqlplus в фоновом режиме и обеспечить его ввод и чтение его вывода (например, emacs).

4

У iBATIS ScriptRunner есть метод setDelimiter(String, boolean). Это позволяет вам иметь строку, отличную от ";" быть разделителем между операторами SQL.

В своем сценарии Oracle SQL отделите операторы с помощью «/» (косой чертой).

В коде Java перед вызовом runScript выполните команду setDelimter("/", false), которая даст указание ScriptRunner распознать разделитель инструкций «/».

+0

Я использую ibatis-common-2.jar, и я не нашел setDelimiter (String , boolean), какую версию iBatis вы используете? – 2014-11-03 07:29:28

7

Используйте приведенное ниже решение для справки, я пробовал и тестировал и работал успешно.

private static String script_location = ""; 
private static String file_extension = ".sql"; 
private static ProcessBuilder processBuilder =null; 

public static void main(String[] args) { 
    try { 
     File file = new File("C:/Script_folder"); 
     File [] list_files= file.listFiles(new FileFilter() { 

      public boolean accept(File f) { 
       if (f.getName().toLowerCase().endsWith(file_extension)) 
        return true; 
       return false; 
      } 
     }); 
     for (int i = 0; i<list_files.length;i++){ 
      script_location = "@" + list_files[i].getAbsolutePath();//ORACLE 
      processBuilder = new ProcessBuilder("sqlplus",  "UserName/[email protected]_name", script_location); //ORACLE 
      //script_location = "-i" + list_files[i].getAbsolutePath(); 
      // processBuilder = new ProcessBuilder("sqlplus", "-Udeep-Pdumbhead-Spc-de-deep\\sqlexpress-de_com",script_location); 
      processBuilder.redirectErrorStream(true); 
      Process process = processBuilder.start(); 
      BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); 
      String currentLine = null; 
      while ((currentLine = in.readLine()) != null) { 
       System.out.println(" " + currentLine); 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    }catch(Exception ex){ 
     ex.printStackTrace(); 
    } 
} 

Используйте этот код фрагмента и пытайтесь запустить.

Thanx пользователю упоминается решение в следующей ссылке:

http://forums.sun.com/thread.jspa?threadID=5413026

С уважением | Нитин

+1

это выглядит как хорошая альтернатива :) спасибо за обмен – 2010-02-15 09:00:07

3

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

Короче говоря, не существует готовые решения для этого: если вы откроете источники Ant или Maven, вы увидите, что они используют простой разветвитель сценариев на основе регулярного выражения, который подходит для простых скриптов, но обычно не выполняется, например, хранимые процедуры. Такая же история с миграциями iBATIS, c5 db и т. Д.

Проблема в том, что существует несколько языков: для запуска «SQL-скриптов» нужно иметь возможность обрабатывать (1) SQL, (2) PL/SQL и (3) sqlplus.

Запуск sqlplus сам по себе действительно так, но создает беспорядок конфигурации, поэтому мы попытались избежать этой опции.

Есть ANTLR-парсеры для PL/SQL, такие как Alexandre Porcelli's one. Это очень близко, но никто не подготовил полное решение для выгрузки, основанное на тех, что до сих пор.

Мы закончили писать yet another ad hoc splitter, который знает о некоторых командах Sqlplus как / и EXIT - это все-таки некрасиво, но работает для большинства наших сценариев. (Обратите внимание, что некоторые скрипты, например, с комментариями --, не будут работать - это все еще kludge, а не решение.)