У меня есть куча сценариев sql, которые должны обновлять базу данных при запуске веб-приложения 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.




sqlplus: да, можно. Я все время запускаю sqlplus из Xemacs (редактора). Итак, вы можете запустить sqlplus в интерпретируемом режиме, а затем предоставить ему команды и прочитать вывод.
Другой способ - загрузить бесплатный инструмент разработчика SQL на основе Java от oracle (http://www.oracle.com/technology/software/products/sql/index.html). он поставляется с утилитой sqlcli.bat, которая является оболочкой над Java-программой. Возможно, вы захотите использовать эту утилиту командной строки для выполнения своей работы.
Подводя итог, я бы попробовал запустить sqlplus в фоновом режиме и предоставить его ввод и прочитать его вывод (как это делает emacs).
Если вы хотите написать свой собственный исполнитель сценариев, вы можете использовать Spring JDBC SimpleJdbcTemplate (http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html).
Вы, конечно, можете загружать сценарии, как и любой другой ресурс в Spring.
Вы можете увидеть реализации других людей. См. Этот ресурс: «SQL-клиенты с открытым исходным кодом на Java» http://java-source.net/open-source/sql-clients
IBATIS ScriptRunner имеет метод setDelimiter(String, boolean). Это позволяет вам иметь строку, отличную от ";" быть разделителем между операторами SQL.
В вашем сценарии Oracle SQL разделите операторы знаком «/» (косая черта).
В вашем Java-коде перед вызовом runScript выполните setDelimter("/", false), который проинструктирует ScriptRunner распознавать «/» как разделитель операторов.
Используйте приведенное ниже решение для справки, я пробовал, тестировал и успешно работал.
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/Password@database_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();
}
}
Используйте этот фрагмент кода и попробуйте запустить.
Спасибо пользователю, который упомянул решение в приведенной ниже ссылке:
http://forums.sun.com/thread.jspa?threadID=5413026
С уважением | Нитин
это похоже на хорошую альтернативу :) спасибо, что поделились
Не так давно столкнулся с той же проблемой, несколько раз сталкивался с вашим вопросом, пока искал решение в Google, так что я думаю, что я вам должен - вот мои выводы на данный момент:
Короче говоря, для этого нет готовых решений: если вы откроете источники Муравей или Maven, вы увидите, что они используют простой разделитель сценариев на основе регулярных выражений, который подходит для простых сценариев, но обычно не работает, например хранимые процедуры. Та же история с iBATIS, миграциями c5 db и т. д.
Проблема в том, что задействовано более одного языка: для запуска «сценариев SQL» необходимо уметь обрабатывать (1) SQL, (2) PL / SQL и (3) команды sqlplus.
Запуск sqlplus - это действительно способ, но он создает путаницу в конфигурации, поэтому мы постарались избежать этого варианта.
Существуют синтаксические анализаторы ANTLR для PL / SQL, такие как Александр Порчелли - они очень близки, но пока никто не подготовил полное решение на основе них.
Мы закончили тем, что написали еще один специальный сплиттер, который знает о некоторых командах sqlplus, таких как / и EXIT - это все еще некрасиво, но работает для большинства наших скриптов. (Обратите внимание, хотя некоторые сценарии, например, с завершающими комментариями --, не будут работать - это все еще путаница, а не решение.)
Я использую ibatis-common-2.jar и не нашел метода setDelimiter (String, boolean). Какую версию iBatis вы используете?