Java ProcessBuilder无法使用sqlplus执行sql脚本文件,而在Linux可以正常执行

发布时间 2023-06-19 10:01:33作者: 229

问题

在 linux 执行 sqlplus 跑sql脚本文件时能够正常执行,当Java ProcessBuilder向Linux Server发送指令时抛出错误

Cannot run program "sqlplus" (in directory "/test/scripts"): error=2, No such file or directory;

解决思路

  1. 如果我们在 linux 环境下能够正常执行sqlplus指令,就说明我们的Server已经正确安装并配置了Oracle相关的环境。
    而我们这时需要找出的是 从 Linux Server 执行 sqlplus 指令从 Java ProcessBuilder 执行 sqlplus 指令 之间的区别
  2. 如果我们从在1)中消耗了很多时间都找不到解决方法时,可能会尝试换一种方式执行sql脚本文件,比如 Spring的ScriptUtils 或者 自定义的工具类

我曾经在 1) 中花费了很多时间并转而使用 2) 中的Spring的ScriptUtils方法,但是Spring的ScriptUtils并没有想象中的适合,更像是读取sql脚本文件然后逐行执行SQL而已,由于我的sql脚本文件中包含了例如 set colsep ',' , spool c:\temp\test.txt; 之类的sqlplus专用关键词,导致使用ScriptUtils.executeSqlScript无法执行,并抛出"missing or invalid option"异常如下:

没办法,只能接着死磕 1) 的解决方法,我开始考虑是否Java ProcessBuilder使用的进程的环境变量与linux server user的环境变量不同导致的。
最终发现是只需要正确设置ORACLE_HOME和PATH即可,要实现这一步需要将qlplus指令改写成shell文件

解决过程

  1. 使用Java ProcessBuilder向Linux Server发送指令,代码如下:
    public String test() throws Exception {

        //String cmd = "sqlplus TEST/TEST123@test < /test/scripts/TEST_TXT.sql";

        //Build command
        List<String> commands = new ArrayList<String>();
        commands.add("sqlplus");
        //Add arguments
        commands.add(dbUsername + "/" + dbPassword + "@ctccbs");
        commands.add("<");
        commands.add("/test/scripts/TEST_TXT.sql");

        //Run macro on target
        ProcessBuilder pb = new ProcessBuilder(commands);
        pb.directory(new File("/test/scripts"));
        pb.redirectErrorStream(true);
        Map<String, String> environment = pb.environment();
        Process process = pb.start();

        //Read output
        StringBuilder out = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        try {
            String line = null;
            String previous = null;
            while ((line = br.readLine()) != null) {
               /* if (!line.equals(previous)) {
                    previous = line;
                    out.append(line).append('\n');
                }*/
            }


            //Check result
            int statusCode = process.waitFor();
            if (statusCode != 0) {
                return "Failed to run sql file with status code: " + statusCode;
            }
        } catch (Exception e) {
            return e.getMessage();
        } finally {
            if (br != null) {
                br.close();
            }
            if (process != null) {
                process.destroy();
            }
        }
        return "Successful";
    }
  1. 结果失败,抛出以下错误信息
Cannot run program "sqlplus" (in directory "/test/scripts"): error=2, No such file or directory;
  1. 创建shell文件,将sqlplus指令写入shell文件中,b并且查看并参照 ~/.bash_profile 文件,重新配置ORACLE_HOME和PATH

  1. 执行成功,数据库中数据成功发生改变,statusCode 为 0 即代表正常执行