SQL 仅当程序是 运行 来自 Runtime.exec() 时才会出现异常

SQL Exception only when program is run from Runtime.exec()

我在理解以下问题时遇到了一些问题。 由于我不会(也不能)在这里说明的原因,我不得不编写一个外部 JAR 以在 Java Web 应用程序中执行,使用绑定到 Runtime.exec() 方法调用的进程。这个外部 JAR 在数据库中执行查询,并使用 Apache POI 库在 Excel 文件中打印其结果。 这是它的代码:

public static void main(String[] args) {

    //Initializing error variable
    boolean error = false;

    //Initializing rownum variable
    int rownum = 0;

    //Initializing db connection parameters
    String userName = args[0];
    String password = args[1];
    String dbUrl = args[2];

    //Initializing file path
    String filePath = args[3];

    //Initializing query string
    String query = args[4];
    if(!query.endsWith(";"))
        query += ";";

    //Keep 100 rows in memory, exceeding rows will be flushed to disk
    SXSSFWorkbook wb = new SXSSFWorkbook(SXSSFWorkbook.DEFAULT_WINDOW_SIZE);

    //Temp files will be gzipped
    wb.setCompressTempFiles(true);

    //Initializing xlsx sheet
    Sheet sh = wb.createSheet();
    wb.setSheetName(wb.getSheetIndex(sh), "DBExtraction");

    //Trying to connect to db and execute a query.
    //If the previous operation succeeded, parse query results
    //into an xlsx workbook
    try {
        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        Connection conn = DriverManager.getConnection(dbUrl, userName, password);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(query);
        ResultSetMetaData md = rs.getMetaData();
        int cols = md.getColumnCount();
        int cn = 0;

        Row header = sh.createRow(rownum++);
        for(int i = 0; i < cols; ++i) {
            header.createCell(cn++).setCellValue(md.getColumnLabel(i + 1));
        }

        while(rs.next()) {
            Row row = sh.createRow(rownum++);
            cn = 0;
            for (int cellnum = 0; cellnum < cols; cellnum++) {
                Cell cell = row.createCell(cellnum);
                cell.setCellValue(rs.getString(++cn));
            }
        }

        for(int j = 0; j < cols; ++j) {
            sh.setColumnWidth(j, 67*256);
        }

        FileOutputStream fos = new FileOutputStream(filePath);

        //Writing workbook to file
        wb.write(fos);

        //Closing file
        fos.flush();
        fos.close();

        //Dispose of temporary files backing this workbook on disk
        wb.dispose();
        wb.close();

        //Closing db connection objects
        rs.close();
        stmt.close();
        conn.close();

    } catch (Exception e) {
        error = true;
        e.printStackTrace();
    }

    if(error)
        System.exit(1);
    else
        System.exit(0);
}

存档中还打包了外部库(Apache POI 和 jar 格式的 SQL 服务器驱动程序)。

当我尝试直接从终端(cmd 或 bash)执行程序时,使用命令 java -jar executable.jar "param1" "param2" ... 一切正常。

当我尝试使用上述方法启动相同的命令时出现问题。

下面是负责调用的代码:

Process p = null;
p = Runtime.getRuntime().exec("java -jar " +
    jarDir +
    File.separator +
    "executable.jar " +
    "\"" + param0 + "\" " +
    "\"" + param1 + "\" " +
    "\"" + param2 + "\" " +
    "\"" + param3 + "\" " +
    "\"" + param4 +"\"");

p.waitFor();
String line;

BufferedReader error = new BufferedReader(new 
    InputStreamReader(p.getErrorStream()));
while((line = error.readLine()) != null){
    System.out.println(line);
}
error.close();

BufferedReader input = new BufferedReader(new 
    InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
    System.out.println(line);
}
input.close();

System.out.println("EXIT VALUE: " + p.exitValue());

在第二种情况下,我得到以下异常: java.sql.SQLException: No suitable driver found for "jdbc:sqlserver://remoteServer:1433;databaseName=dbName".

Web 应用程序目前 运行 在 CentOS7 服务器上的 Wildfly 10.0.0-Final 上。

感谢您的宝贵时间。

编辑: 我认为添加 JAR 清单可能是个好主意,因为它可能包含一些错误(JAR 文件是由 Eclipse 导出生成的):MANIFEST.MF.

此外,这是 JAR 内部结构:JAR Structure

我终于设法解决了这个问题,但是以一种非常低效(而且非常丑陋)的方式。

我必须创建一个 shell 脚本来解析外部 JAR 参数,因为从调用 JAR 的 Web 应用程序方法和实际终端转换引号 (") 字符时出现一些问题。一旦我做到了这一点,JAR 应用程序就像一个魅力。

我不打算提供 shell 脚本源(除非明确要求),因为我为自己感到羞耻。不是关于代码本身,而是关于这个 "workaround".