从java运行oracle sql脚本

发布于 2024-07-06 11:38:44 字数 1832 浏览 8 评论 0原文

我有一堆 sql 脚本,应该在 java web 应用程序启动时升级数据库。

我尝试使用 ibatis scriptrunner,但是在定义触发器时它失败了,其中“;” 字符不标记语句的结束。

现在我已经编写了自己的脚本运行程序版本,它基本上完成了工作,但破坏了可能的格式和注释,特别是在“创建或替换视图”中。

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 语法的了解有限。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

淡淡的优雅 2024-07-13 11:38:44

使用以下解决方案供您参考,我已经尝试并测试并成功运行。

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

问候 | 镍丁

Use below solution for your reference , i have tried and tested and running successfully.

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

Use this snippet code and try and run.

Thanx to user mentioned the solution in the below link:

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

Regards | Nitin

ら栖息 2024-07-13 11:38:44

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

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

在 Java 代码中,在调用 runScript 之前执行 setDelimter("/", false),这将指示 ScriptRunner 将“/”识别为语句分隔符。

The iBATIS ScriptRunner has a setDelimiter(String, boolean) method. This allows you to have a string other than ";" to be the separator between SQL statements.

In your Oracle SQL script, separate the statements with a "/" (slash).

In your Java code, before calling the runScript do a setDelimter("/", false) which will instruct the ScriptRunner to recognize "/" as statement separator.

岁月苍老的讽刺 2024-07-13 11:38:44

不久前遇到了同样的问题,在谷歌搜索解决方案时多次遇到你的问题,所以我想我欠你——这是我迄今为止的发现:

简而言之,没有现成的解决方案:如果你打开< a href="http://java2s.com/Open-Source/Java-Document-2/Database/solidbase/solidbase/core/SQLSource.java.htm" rel="nofollow">Ant 或 Maven 来源,您会看到他们使用一个简单的基于正则表达式的脚本拆分器,这对于简单脚本来说很好,但通常在存储过程等方面失败。 iBATIS、c5 数据库迁移等也是如此。

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

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

有用于 PL/SQL 的 ANTLR 解析器,例如 Alexandre Porcelli 的解析器 - 它们非常接近,但是到目前为止,还没有人根据这些方案准备出完整的即插即用解决方案。

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

Had the same problem not so long ago, bumped into your question several times while googling for a solution, so I think I owe you—here are my findings so far:

In brief, there are no ready solutions for that: if you open Ant or Maven sources, you'll see they are using a simple regexp-based script splitter which is fine for simple scripts, but usually fails on e.g. stored procedures. Same story with iBATIS, c5 db migrations, etc.

The problem is, there's more than one language involved: in order to run "SQL Scripts" one must be able to handle (1) SQL, (2) PL/SQL, and (3) sqlplus commands.

Running sqlplus itself is the way indeed, but it creates configuration mess, so we tried to avoid this option.

There are ANTLR parsers for PL/SQL, such as Alexandre Porcelli's one—those are very close, but no one prepared a complete drop-in solution based on those so far.

We ended up writing yet another ad hoc splitter which is aware of some sqlplus commands like / and EXIT— it's still ugly, but works for most of our scripts. (Note though some scripts, e.g., with trailing -- comments, won't work—it's still a kludge, not a solution.)

兔姬 2024-07-13 11:38:44

sqlplus:是的,可以。 我一直在 Xemacs(editor) 中运行 sqlplus。 因此,您可以在解释模式下运行 sqlplus,然后向其提供命令并读取输出。

另一种方法是从 oracle 下载基于 java 的免费 SQL 开发工具 (http ://www.oracle.com/technology/software/products/sql/index.html)。 它附带了一个 sqlcli.bat 实用程序,它是 java 程序的包装器。 您可能想使用此命令行实用程序来完成您的工作。

总之,我会尝试在后台运行 sqlplus 并提供它的输入并读取它的输出(就像 emacs 那样)。

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).

扶醉桌前 2024-07-13 11:38:44

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

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

If you want to write your own script runner, you can use Spring JDBC's SimpleJdbcTemplate (http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html).

You can, of course, load the scripts as you would any resource in Spring as well.

你对谁都笑 2024-07-13 11:38:44

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

You can see other people's implementations. See this resource: "Open Source SQL Clients in Java" http://java-source.net/open-source/sql-clients

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文