java - 使用 JDBC 从 dbms_output.get_lines 获取输出

标签 java sql oracle jdbc plsql

如何使用 JDBC 在 Java 应用程序中获取 Oracle 的 dbms_output.get_lines 的输出而不在数据库中创建额外的对象

最佳答案

I've also blogged about this issue here .下面是一个片段,说明了如何做到这一点:

try (CallableStatement call = c.prepareCall(
    "declare "
  + "  num integer := 1000;" // Adapt this as needed
  + "begin "

  // You have to enable buffering any server output that you may want to fetch
  + "  dbms_output.enable();"

  // This might as well be a call to third-party stored procedures, etc., whose
  // output you want to capture
  + "  dbms_output.put_line('abc');"
  + "  dbms_output.put_line('hello');"
  + "  dbms_output.put_line('so cool');"

  // This is again your call here to capture the output up until now.
  // The below fetching the PL/SQL TABLE type into a SQL cursor works with Oracle 12c.
  // In an 11g version, you'd need an auxiliary SQL TABLE type
  + "  dbms_output.get_lines(?, num);"

  // Don't forget this or the buffer will overflow eventually
  + "  dbms_output.disable();"
  + "end;"
)) {
    call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
    call.execute();

    Array array = null;
    try {
        array = call.getArray(1);
        System.out.println(Arrays.asList((Object[]) array.getArray()));
    }
    finally {
        if (array != null)
            array.free();
    }
}

以上将打印:

[abc, hello, so cool, null]

请注意,ENABLE/DISABLE 设置是一个连接范围的设置,因此您也可以通过多个 JDBC 语句执行此操作:

try (Connection c = DriverManager.getConnection(url, properties);
     Statement s = c.createStatement()) {

    try {
        s.executeUpdate("begin dbms_output.enable(); end;");
        s.executeUpdate("begin dbms_output.put_line('abc'); end;");
        s.executeUpdate("begin dbms_output.put_line('hello'); end;");
        s.executeUpdate("begin dbms_output.put_line('so cool'); end;");

        try (CallableStatement call = c.prepareCall(
            "declare "
          + "  num integer := 1000;"
          + "begin "
          + "  dbms_output.get_lines(?, num);"
          + "end;"
        )) {
            call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
            call.execute();
    
            Array array = null;
            try {
                array = call.getArray(1);
                System.out.println(Arrays.asList((Object[]) array.getArray()));
            }
            finally {
                if (array != null)
                    array.free();
            }
        }
    }
    finally {
        s.executeUpdate("begin dbms_output.disable(); end;");
    }
}

另请注意,这将获取最多 1000 行的固定大小。如果您需要更多行,您可能需要在 PL/SQL 中循环或轮询数据库。

使用 jOOQ 来做到这一点

请注意,如果您是 jOOQ用户,您可以根据查询自动获取服务器输出:

DSLContext ctx = DSL.using(c, 
    new Settings().withFetchServerOutputSize(10));

然后您应该看到 FetchServerOutputListener 的一些 DEBUG 日志输出,例如

DEBUG [LoggerListener           ] Executing query : begin my_procedure(1, 2); end;
DEBUG [FetchServerOutputListener] <output here>       

除了上述DEBUG 日志之外,您还将在ExecuteContext::serverOutput 中获得信息。

This is also mentioned in the linked blog post

关于调用 DBMS_OUTPUT.GET_LINE 的注意事项

以前,有一个现已删除的答案建议单独调用 DBMS_OUTPUT.GET_LINE,一次返回一行。我已经对方法进行了基准测试,将它与 DBMS_OUTPUT.GET_LINES 进行了比较,差异非常大——从 JDBC 调用时速度最多慢 30 倍(即使从PL/SQL)。

因此,使用 DBMS_OUTPUT.GET_LINES 的批量数据传输方法绝对值得。这是基准测试的链接:

https://blog.jooq.org/the-cost-of-jdbc-server-roundtrips/

关于java - 使用 JDBC 从 dbms_output.get_lines 获取输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47830370/

相关文章:

sql - 在 MSSQL 中打印某一特定查询时遇到困难

oracle - 修改多个oracle触发器

java - Spring NamedParameterJdbcTemplate 查询的性能非常慢

java - 如何识别手机是否空闲?

java - 使用 gwt 和 jsp 时 jetty 类路径出现问题

sql - Oracle Date数据类型,通过SQL转换为 'YYYY-MM-DD HH24:MI:SS TMZ'

sql - 按别名分组 (Oracle)

Java:如何在不使用 Sort() 的情况下基于自定义对象 ArrayList 创建排序字符串 ArrayList

java - 如果我使用自己的 key ,为什么需要散列?

php - 删除重复条目 : Delete a entry that has 2 the same column