11

i have a bunch of sql scripts that should upgrade the database when the java web application starts up.

i tried using the ibatis scriptrunner, but it fails gloriously when defining triggers, where the ";" character does not mark an end of statement.

now i have written my own version of a script runner, which basically does the job, but destroys possible formatting and comments, especially in "create or replace view".

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

is there a clean way to acieve this? is there something in hibernate i have not seen? or can i pass an inputstream to sqlplus somehow? besides my worries about the formatting, i doubt that this code is error-free, since i have limited knowledge about the pl/sql syntax.

4

6 回答 6

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

问候 | 尼丁

于 2010-02-12T12:50:47.157 回答
5

iBATIS ScriptRunner 有一个setDelimiter(String, boolean)方法。这允许您拥有除“;”之外的字符串 作为 SQL 语句之间的分隔符。

在您的 Oracle SQL 脚本中,用“/”(斜杠)分隔语句。

在您的 Java 代码中,在调用runScriptdo a之前setDelimter("/", false),它将指示 ScriptRunner 将“/”识别为语句分隔符。

于 2008-10-24T08:45:01.413 回答
3

不久前有同样的问题,在谷歌搜索解决方案时多次碰到你的问题,所以我想我欠你 - 这是我到目前为止的发现:

简而言之,没有现成的解决方案:如果您打开AntMaven源代码,您会看到它们使用了一个简单的基于正则表达式的脚本拆分器,这对于简单的脚本来说很好,但通常在存储过程中会失败。iBATIS、c5 db 迁移等也是如此。

问题是,涉及的语言不止一种:为了运行“SQL 脚本”,必须能够处理 (1) SQL、(2) PL/SQL 和 (3) sqlplus 命令。

运行sqlplus本身确实是一种方式,但它会造成配置混乱,所以我们试图避免这个选项。

有用于 PL/SQL 的 ANTLR 解析器,例如Alexandre Porcelli 的解析器——它们非常接近,但到目前为止还没有人在这些解析器的基础上准备完整的嵌入式解决方案。

我们最终编写了另一个 ad hoc 拆分器,它知道一些 sqlplus 命令,比如/EXIT- 它仍然很丑,但适用于我们的大多数脚本。(请注意,尽管某些脚本(例如,带有尾随--注释的脚本)不起作用——它仍然是一个组合,而不是一个解决方案。)

于 2011-10-19T07:58:30.763 回答
2

sqlplus : yes you can. I run sqlplus from within Xemacs(editor) all the time. So, you can run sqlplus in an interpreted mode and then provide it commands and read the output as well.

Another ways is to download the free java based SQL developer tool from oracle (http://www.oracle.com/technology/software/products/sql/index.html). it comes with a sqlcli.bat utility which is a wrapper over a java program. You might want to use this command line utility to do your work.

summary, I would try running sqlplus in the background and provide it's input and reading its output (like emacs does).

于 2008-10-14T10:07:38.007 回答
0

如果您想编写自己的脚本运行器,可以使用 Spring JDBC 的 SimpleJdbcTemplate ( http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html )。

当然,您也可以像加载 Spring 中的任何资源一样加载脚本。

于 2008-10-14T10:41:35.770 回答
0

你可以看到其他人的实现。请参阅此资源:“Java 中的开源 SQL 客户端” http://java-source.net/open-source/sql-clients

于 2008-10-19T09:59:35.880 回答